#if 0
#elif defined(__arm64__) && __arm64__
-// Generated by Apple Swift version 6.0.2 effective-5.10 (swiftlang-6.0.2.1.2 clang-1600.0.26.4)
+// Generated by Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
#ifndef JOYGEMAI_SWIFT_H
#define JOYGEMAI_SWIFT_H
#pragma clang diagnostic push
/// 初始化sdk
- (void)initSdk;
+/// 初始化sdk
+/// - Parameter projectID: 可选方法
+- (void)initSdk:(nullable NSString*)projectID;
+
/// 日志打印级别
/// - Parameter level: 日志等级 分为关闭,简略,完全
- (void)setLogMode:(JoyGemLogMode)mode;
/// - speed: 默认1.0,范围[0.8,2]
-(void)setTtsSpeed:(float)speed;
+/// 配置测试环境
+/// - Parameters:
+/// - info: 测试环境字典
+-(void)setDebugEnvironment:(NSDictionary*)info;
+
@end
NS_ASSUME_NONNULL_END
///AI语音接收
/// - Parameters:
/// - data: 音频数据 pcm格式
--(void)chatManager:(JoyGemChatManager*)manager audioData:(nullable NSData*)data finish:(BOOL)isFinish;
+/// - index: 语句ID
+/// - sampleRate: 采样率
+/// - finish: 该句是否结束
+-(void)chatManager:(JoyGemChatManager*)manager audioData:(nullable NSData*)data index:(NSUInteger)index sampleRate:(NSUInteger)sampleRate finish:(BOOL)isFinish;
///用户语音识别
/// - Parameters:
/// - mode:错误代码
-(void)chatManager:(JoyGemChatManager*)manager onError:(JoyGemErrorCode)code;
+@optional
+-(void)chatManagerStopped:(JoyGemChatManager*)manager DEPRECATED_MSG_ATTRIBUTE("Use isActive");
+
@end
//AI对话的管理类
/// - custom: 自定义EQ类型
-(void)getCustomEQ:(void (^)(JoyGemCustomEQ*))custom error:(void (^)( NSError * _Nullable err))error;
-
/// 查找耳机
/// - Parameters:
/// - mode: 查找耳机命令类型
-(void)findHeadphone:(JoyGemFindHeadphoneMode)mode callback:(void (^)( NSError * _Nullable err))error;
+/// 获取设备DN码
+/// - Parameters:
+/// - dn: 设备DN,取不到则返回空值
+-(void)getDN:(void (^)(NSString*))dn error:(void (^)( NSError * _Nullable err))error;
@end
// swift-interface-format-version: 1.0
-// swift-compiler-version: Apple Swift version 6.0.2 effective-5.10 (swiftlang-6.0.2.1.2 clang-1600.0.26.4)
+// swift-compiler-version: Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
// swift-module-flags: -target arm64-apple-ios13.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -enable-bare-slash-regex -module-name JoyGemAI
// swift-module-flags-ignorable: -no-verify-emitted-module-interface
import Foundation
// swift-interface-format-version: 1.0
-// swift-compiler-version: Apple Swift version 6.0.2 effective-5.10 (swiftlang-6.0.2.1.2 clang-1600.0.26.4)
+// swift-compiler-version: Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
// swift-module-flags: -target arm64-apple-ios13.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -enable-bare-slash-regex -module-name JoyGemAI
// swift-module-flags-ignorable: -no-verify-emitted-module-interface
import Foundation
<dict>
<key>Headers/JoyGemAI-Swift.h</key>
<data>
- EzwLstWsXu+VfPMQanIZDbX3a0E=
+ okSjIYqQdjYFuhBqjGvwfYh8+aU=
</data>
<key>Headers/JoyGemAI.h</key>
<data>
</data>
<key>Headers/JoyGemAIManager.h</key>
<data>
- Oq+OIkczOsgav5Qo1BqTz/1gc4M=
+ D/pnfOpF7qKhUfhoTsKEfdEQQRQ=
</data>
<key>Headers/JoyGemCallManager.h</key>
<data>
</data>
<key>Headers/JoyGemChatManager.h</key>
<data>
- EOl/+6HcGPZVHgre1chnDptuCBU=
+ I9SSrf6xzcSE2qKnMMmiSe9IV1I=
</data>
<key>Headers/JoyGemDeviceManager.h</key>
<data>
- h7T4t0GUmAg2ZHyPU+Sn7lQrkw0=
+ GnuSbYAD+3F7R21VuV35n97Bubk=
</data>
<key>Headers/JoyGemEnum.h</key>
<data>
</data>
<key>Info.plist</key>
<data>
- vHVrQqK4ReuQBxyUxqv5BOG8mbw=
+ yyyfSn0pDOYFx2gtlmBDVpKhVxw=
</data>
<key>Modules/JoyGemAI.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo</key>
<data>
- jacBwduET4BLcaiJtoJ9sWWXQ6s=
+ CPeqh4HaaR/F9LP2LFiPwE3Qxzo=
</data>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.abi.json</key>
<data>
</data>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.private.swiftinterface</key>
<data>
- BmjRZIKCen7GN8lmcoDVw3R2KvM=
+ sOTjmG3OZu9FvWVYyTuqSix+tzU=
</data>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftdoc</key>
<data>
- xFskxbeAbkxTqKE8F2wcvY/ElFM=
+ s/YEyU+lH4pYoG62jihLM2SJPTU=
</data>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftinterface</key>
<data>
- BmjRZIKCen7GN8lmcoDVw3R2KvM=
+ sOTjmG3OZu9FvWVYyTuqSix+tzU=
</data>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftmodule</key>
<data>
- 4QozN8a+2xPGGnyDrUz/2Hg7JPI=
+ OKLv2mrRkW9EiT9AdyIjFh6WmI8=
</data>
<key>Modules/module.modulemap</key>
<data>
<dict>
<key>hash2</key>
<data>
- D6FOg3LxVu6AQ3xMxdtxm8TsqeXBLCKYS1SQ1weJXno=
+ Jktn0pvS86rbDKXpgT8xSUtpGRzWvf2yzqxwqMqFKS4=
</data>
</dict>
<key>Headers/JoyGemAI.h</key>
<dict>
<key>hash2</key>
<data>
- IThULWmQt2RS9f8uhIVCj/9ZZKa5G20vUaJzCby0P9U=
+ hAXAZoFB6Ja0kc5Gm3Bo952k9fZUiSUPYM2f9gyTkQw=
</data>
</dict>
<key>Headers/JoyGemCallManager.h</key>
<dict>
<key>hash2</key>
<data>
- 4ZkuysTzaFha4/myXFF57XtlqM0e4bMJIZlamlMNqm8=
+ v9CC1YyWez/AeMXpqpyouz+LNIkBqq147kBPoPYEVK8=
</data>
</dict>
<key>Headers/JoyGemDeviceManager.h</key>
<dict>
<key>hash2</key>
<data>
- zMSjXsvAeHKCWlyAIRTc/D/BYBU8crV81VAMtiRCNZA=
+ b8SW0vyfvdZ5JjAexckdczSXWjl11+WIJDM6wuHhBEo=
</data>
</dict>
<key>Headers/JoyGemEnum.h</key>
<dict>
<key>hash2</key>
<data>
- ppJvM28BX4SQ+Bp40K+I9948VA34G8v2sowJEtO80vQ=
+ dSyxVyC1vMbliDqKuW0d31f2wCYxeWsx2/NHJQYPrRc=
</data>
</dict>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.abi.json</key>
<dict>
<key>hash2</key>
<data>
- c9qIPe1Wqd1NpKlpuawO+ORLNw5ws9/SFWK8GiWvotQ=
+ Xu9oOK+bUwZsz7YKaBS7sdDWZvQJwX6GCeM7UKDOIew=
</data>
</dict>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftdoc</key>
<dict>
<key>hash2</key>
<data>
- lFffbgJPWht+xRXKPA4Nv2rrNTUSt2wtt9PtaTTwK6w=
+ 4ZSTOVNx5VInV3CLCGXGsOKMICdleteG1O8aHABZCzw=
</data>
</dict>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftinterface</key>
<dict>
<key>hash2</key>
<data>
- c9qIPe1Wqd1NpKlpuawO+ORLNw5ws9/SFWK8GiWvotQ=
+ Xu9oOK+bUwZsz7YKaBS7sdDWZvQJwX6GCeM7UKDOIew=
</data>
</dict>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftmodule</key>
<dict>
<key>hash2</key>
<data>
- oIPD6jOI3lmqwRw8fQIjIdbh/igLDvY7QXuX2vHol4M=
+ nRKcutC82zySWegf6JkCelatcDI5wxHUuHo6O2D+Osc=
</data>
</dict>
<key>Modules/module.modulemap</key>
- TZImagePickerController/Location (3.8.9)
- YYModel (1.0.4)
- YYText (1.0.7)
+ - ZipArchive (1.4.0)
DEPENDENCIES:
- CryptoSwift
- TZImagePickerController
- YYModel
- YYText
+ - ZipArchive
SPEC REPOS:
https://gitee.com/mirrors/CocoaPods-Specs.git:
- TZImagePickerController
- YYModel
- YYText
+ - ZipArchive
SPEC CHECKSUMS:
CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90
TZImagePickerController: 456f470b5dea97b37226ec7a694994a8663340b2
YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
+ ZipArchive: e25a4373192673e3229ac8d6e9f64a3e5713c966
-PODFILE CHECKSUM: 1495066f701d18df80b99c90e3a4f415fed5c214
+PODFILE CHECKSUM: 2a2c83c3c610795228576bbe8899f7939f0e6d43
COCOAPODS: 1.16.2
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
- inputPaths = (
- );
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
- outputPaths = (
- );
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ShenYin/Pods-ShenYin-frameworks.sh\"\n";
CODE_SIGN_ENTITLEMENTS = ShenYin/ShenYin.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = M33X987285;
+ DEVELOPMENT_TEAM = G23X75CJ67;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
CODE_SIGN_ENTITLEMENTS = ShenYin/ShenYin.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = M33X987285;
+ DEVELOPMENT_TEAM = G23X75CJ67;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
case musicCategoryList(categoryId:String,page:Int)
/// 获取音乐地址
case musicUrl(filedId:String)
+ /// 获取录音文件地址
+ case recordUrl(filedId:String)
/// 上传图片
case uploadImage(param:[String:Any])
/// 获取产品列表
case bannerList
/// banner点击统计
case bannerClick(bannerId:String)
+
+ /// 上传录音文件
+ case uploadVoiceFile(param:[String:Any])
+ /// 创建录音记录
+ case voiceRecord(param:[String:Any])
+ /// 获取录音记录
+ case getVoiceRecord(recordId:String)
+ /// 更新录音
+ case updateVoiceRecord(param:[String:Any])
+ /// 删除录音
+ case deleteVoiceRecord(recordId:String)
+ /// 获取录音列表
+ case voiceRecordList(param:[String:Any])
+ ///收藏,或者取消收藏
+ case voiceRecordCollection(param:[String:Any])
}
// 实现TargetType协议
return "/res/sleep-music/list/\(page)?categoryId=\(categoryId)"
case .musicUrl( let id):
return "/res/music-file/path/\(id)"
+ case .recordUrl( let id):
+ return "/res/voice-file/play/\(id)"
+
case .uploadImage(_):
return "/res/image"
+ case .uploadVoiceFile(_):
+ return "/res/voice-file/upload"
case .getProductList:
- return "/dev/product/list"
+ return "/dev/product/list/\(BleManager.shared.connectPeripheral?.device.name ?? "")"
case .productBook(let productId):
return "/res/prod-book-file?productId=\(productId)"
case .qaCategory:
case .bannerList:
return "/res/banner/list"
case .bannerClick(let bannerId):
- return "/res/banner/click/\(bannerId)"
+ return "/res/banner/click/\(bannerId)"
+
+
+ case .voiceRecord(_):
+ return "/res/voice-record"
+ case .getVoiceRecord(let recordId):
+ return "/res/voice-record/\(recordId)"
+ case .updateVoiceRecord(let param):
+ return "/res/voice-record/\(param["id"]!)"
+ case .deleteVoiceRecord(let recordId):
+ return "/res/voice-record/\(recordId)"
+ case .voiceRecordList(let param):
+ return "/res/voice-record/list/\(param["page"]!)"
+ case .voiceRecordCollection(let param):
+ return "/res/voice-record/favorite/\(param["recordId"]!)?favorite=\(param["favorite"]!)"
+
+
}
}
var method:RequestMethod{
switch self {
- case .register(_),.phoneCodeLogin(_),.emailCodeLogin(_),.login(_),.commitFeedback(_):
+ case .register(_),.phoneCodeLogin(_),.emailCodeLogin(_),.login(_),.commitFeedback(_),.voiceRecord(_):
return .post
- case .updatePwd(_),.updateUserInfo(_),.updatePhone(_),.updateEmail(_),.bindDevice(_),.otaUpdateVersion(_):
+ case .updatePwd(_),.updateUserInfo(_),.updatePhone(_),.updateEmail(_),.bindDevice(_),.otaUpdateVersion(_),.voiceRecordCollection(_),.updateVoiceRecord(_):
return .put
- case .deleteLoginRecord(_),.unbind(_):
+ case .deleteLoginRecord(_),.unbind(_),.deleteVoiceRecord(_):
return .delete
default:
return .get
// 收集参数
switch self {
-// case let .sms(phone, type):
-// params["phone"] = phone
-// params["type"] = type.value
case let .list(pageNO, pageSize):
params["pageNO"] = pageNO
params["pageSize"] = pageSize
case let .uploadImage(para):
params += para
break
+ case let .uploadVoiceFile(para):
+ params += para
+ break
case let .commitFeedback(para):
params += para
break
case let .bindDevice(para):
params += para
break
+ case let .voiceRecord(para):
+ params += para
+ case let .voiceRecordList(para):
+ params += para
+ case let .updateVoiceRecord(para):
+ params += para
default:
break
}
}
}
+ static func uploadVoiceFile1<T: HandyJSON>(_ target: CommomApi,completionHandler:@escaping ((T, String) -> Void)) {
+ Logger.debug("request => ",target.url)
+ guard let fileUrl = target.param["fileUrl"] as? URL else {
+ Logger.debug("后",target.param)
+ return
+ }
+ if FileManager.default.fileExists(atPath: fileUrl.path){
+ Logger.debug("文件存在")
+ }
+ else{
+ Logger.debug("文件不存在")
+ }
+ Logger.debug(fileUrl)
+ let request = HTTP.POST(target.url, parameters: ["form-data": Upload(fileUrl: fileUrl)]) { response in
+ handleResponse(response, completionHandler: completionHandler)
+ }
+ request?.progress = { progress in
+ Logger.debug("上传进度: \(progress)%")
+ }
+ }
+ static func uploadVoiceFile<T: HandyJSON>(_ target: CommomApi,completionHandler:@escaping ((T, String) -> Void)) {
+ Logger.debug("request => ",target.url)
+ guard let fileUrl = target.param["fileUrl"] as? URL else {
+ Logger.debug("后",target.param)
+ return
+ }
+ if FileManager.default.fileExists(atPath: fileUrl.path){
+ Logger.debug("文件存在")
+ }
+ else{
+ Logger.debug("文件不存在")
+ }
+ Logger.debug(fileUrl)
+ guard let fileData = readFile(from: fileUrl.path) else {
+ return
+ }
+
+ let url = URL(string: target.url)!
+ var request = URLRequest(url: url)
+
+ request.httpMethod = "POST"
+ request.addValue("application/json", forHTTPHeaderField: "Accept")
+ request.addValue("multipart/form-data", forHTTPHeaderField: "Content-Type")
+// request.setValue("Bearer \(aiKey)", forHTTPHeaderField: "Authorization")
+ request.addValue("gzip", forHTTPHeaderField: "Accept-Encoding")
+
+ // Audio file is sent to OpenAI as multipart form data. There is probably an easier way to do this with a built-in library
+ let boundary = UUID().uuidString
+ request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
+
+ var formData = Data()
+ formData.append("--\(boundary)\r\n".data(using: .utf8)!)
+ formData.append("Content-Disposition: form-data; name=\"file\"; filename=\"record.wav\"\r\n".data(using: .utf8)!)
+ formData.append("\r\n".data(using: .utf8)!)
+ formData.append(fileData)
+ formData.append("\r\n".data(using: .utf8)!)
+
+ // This specifies the model to use "whisper-1"
+ formData.append("--\(boundary)\r\n".data(using: .utf8)!)
+ formData.append("Content-Disposition: form-data; name=\"model\"\r\n\r\nwhisper-1\r\n".data(using: .utf8)!)
+
+ formData.append("--\(boundary)--\r\n".data(using: .utf8)!)
+
+ request.httpBody = formData
+
+ let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
+ handleResponse1(data, error: error, completionHandler: completionHandler)
+ }
+ task.resume()
+ }
+
static func uploadImage<T: HandyJSON>(_ target: CommomApi,completionHandler:@escaping ((T, String) -> Void)) {
Logger.debug("request => ",target.url)
guard let fileUrl = target.param["fileUrl"] as? URL else {
}
}
- static func download(url:String,fileId:String,completionHandler:@escaping ((String?) -> Void)){
+ static func download(url:String,type:String,completionHandler:@escaping ((String?) -> Void)){
Logger.debug("dowload => ",url)
if let request = URLRequest(urlString:url) {
let task = HTTP(request, isDownload: true)
}
task.downloadHandler = { response, tempUrl in
DispatchQueue.main.sync {
- if let destinationUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("\(fileId).mp3") {
+ let name = Date().format(.full5)
+ if let destinationUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("\(name).\(type)") {
if FileManager.default.fileExists(atPath: destinationUrl.path) {
Logger.debug("文件已经存在,先移除 => ",url)
do {
}
}
}
+ private static func handleResponse1<T: HandyJSON>(_ data: Data?,error:Error?, completionHandler: @escaping ((T, String) -> Void)) {
+ DispatchQueue.main.sync {
+ if let error = error {
+ Logger.debug(error)
+ completionHandler(T(),"请求失败")
+ return
+ }
+ guard let data = data else{
+ completionHandler(T(),"请求失败")
+ return
+ }
+ Logger.debug(data.string ?? "")
+ guard let dict = data.jsonObject() as? NSDictionary else{
+ completionHandler(T(),"请求失败")
+ return
+ }
+ let responseStr = data.string ?? ""
+ if let res = T.deserialize(from: dict){
+ completionHandler(res,responseStr)
+ return
+ }
+ completionHandler(T(),"请求失败")
+ if let code = dict["code"] as? Int,code == 50001{
+ YLprogressHUD.showAutoHiden(text: "当前账号已经退出登录"){
+ CacheManager.shared.logout()
+ }
+ }
+ }
+ }
static func receiveData(_ response:Response) ->(NSDictionary?){
if let _ = response.error {
Logger.debug(data.string ?? "")
return (dict)
}
-
+ static func readFile(from path:String) ->Data?{
+ let fileURL = URL(fileURLWithPath: path)
+ do {
+ let data = try Data(contentsOf:fileURL)
+ return data
+ } catch {
+ return nil
+ }
+ }
}
extension Data {
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Group_2372@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Group_2372@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Frame 1938@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Frame 1938@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Frame 1938@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Frame 1938@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Frame 1938@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Frame 1938@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Group_2274@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Group_2274@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Group_2285@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Group_2285@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "Group_2275@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "Group_2275@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
--- /dev/null
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x"
+ },
+ {
+ "filename" : "天气_多云_1@2x.png",
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "filename" : "天气_多云_1@3x.png",
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>NSAppTransportSecurity</key>
+ <dict>
+ <key>NSAllowsArbitraryLoads</key>
+ <true/>
+ </dict>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<string>bluetooth-central</string>
<string>audio</string>
</array>
- <key>NSAppTransportSecurity</key>
- <dict>
- <key>NSAllowsArbitraryLoads</key>
- <true/>
- </dict>
</dict>
</plist>
//#import "SVProgressHUD+YLAdd.h"
#import "YLTimerButton.h"
#import "PcmSound.h"
-
+#import <zlib.h>
static let full2: Format = .init("yyyy-MM-ddTHH:mm")
static let full3: Format = .init("yyyy-MM-dd HH:mm")
static let full4: Format = .init("yyyyMMdd00000000")
+ static let full5: Format = .init("yyyyMMddHHmmss")
+ static let full6: Format = .init("yyyyMMddHHmmssSSS")
}
/// 格式化成本地时间
// Created by liangshi on 2025/9/22.
//
import Foundation
+import AVKit
class YLToos {
static func formatSeconds(_ totalSeconds: Int) -> String {
let seconds = totalSeconds % 60
return String(format: "%02d:%02d", minutes, seconds)
}
+
+ static func getDuration(_ path: String) -> Int {
+ let fileURL = URL(fileURLWithPath: path)
+ let asset = AVAsset(url: fileURL)
+ let duration = asset.duration
+ let t = CMTimeGetSeconds(duration)
+ return Int(t)
+ }
}
bar.startAnimating {[weak self] in
guard let self = self else{return}
//toolBar.recordBtn.stopCli()
+ guard let path = recordFilePath else{return}
let v = PopTextField()
v.show()
v.cancelTap = {
}
- v.okTap = {
+ v.okTap = { [weak self] text in
+ guard let self = self else{return}
+ let model = RecordDetailModel()
+ model.type = .phone
+ model.from = bar.leftItem.language
+ model.to = .english
+ model.name = text
+ model.path = path
+ model.duration = YLToos.getDuration(model.path)
+ model.origin = textView.text
+ model.translate = ""
+
+ App.shared.goToPage(RecordDetailVC(record: model))
}
}
}
}
func callManager(_ manager: JoyGemCallManager, saveFile path: String) {
- debugPrint("path: \(path)")
+ Logger.debug("path: \(path)")
recordFilePath = path
}
}
extension ChatVC : JoyGemChatManagerDelegate {
+ func chatManager(_ manager: JoyGemChatManager, audioData data: Data?, index: UInt, sampleRate: UInt, finish isFinish: Bool) {
+
+ }
+
func chatManager(_ manager: JoyGemChatManager, stateChange code: JoyGemStateCode) {
- Logger.debug("事shi ",code)
+ Logger.debug("事件 ",code)
switch code {
case .startRecord:
toolBar.isRecord = true
let bg = UIImageView()
var dataList:[(Chinese2EnglishCellModel,UInt)] = []
var pcmData = Data()
+ var recordFilePath : String?
override func setupViews() {
navBar.title = "中英互译"
bar.startAnimating {[weak self] in
guard let self = self else{return}
// toolBar.recordBtn.stopCli()
+ guard let path = recordFilePath else{return}
let v = PopTextField()
v.show()
v.cancelTap = {
}
- v.okTap = {
+ v.okTap = { [weak self] text in
+ guard let self = self else{return}
+ var origin = ""
+ var translate = ""
+ for (item,_) in dataList {
+ origin += item.send + "\n"
+ translate += item.response + "\n"
+ }
+
+ let model = RecordDetailModel()
+ model.type = .translate
+ model.from = bar.leftItem.language
+ model.to = bar.rightItem.language
+ model.name = text
+ model.path = path
+ model.duration = YLToos.getDuration(model.path)
+ model.origin = origin
+ model.translate = translate
+ App.shared.goToPage(RecordDetailVC(record: model))
}
}
}
}
func siDeviceManager(_ manager: JoyGemSIDeviceManager, didUpdateRaw model: JoyGemAsrModel) {
- debugPrint("text: \(model.text),index: \(model.index)")
+ Logger.debug("text: \(model.text),index: \(model.index)")
let msg = dataList.firstIndex (where: { (str,idx) in
return idx == model.index;
})
}
func siDeviceManager(_ manager: JoyGemSIDeviceManager, saveFile path: String) {
- debugPrint("path: \(path)")
+ Logger.debug("path: \(path)")
+ recordFilePath = path
}
func siDeviceManager(_ manager: JoyGemSIDeviceManager, stateChange code: JoyGemStateCode) {
- debugPrint("code: \(code)")
+ Logger.debug("code: \(code)")
}
func siDeviceManager(_ manager: JoyGemSIDeviceManager, onError code: JoyGemErrorCode) {
var model:HomeDeviceModel!{
didSet{
- titleLabel.text = model.productName + model.mac.prefix(5)
-
+// titleLabel.text = model.productName + model.mac.prefix(5)
+ titleLabel.text = model.productName
+
icon.kf.setImage(with: model.image.yc.asUrl)
if BleManager.shared.isConected(mac: model.mac) {
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
+// let model = DeviceVM.shared.dataList[indexPath.row]
+// if BleManager.shared.isConected(mac: model.mac) {
+// App.shared.goToPage(HomeVC(device: model))
+// return
+// }
+// ConnectPopView.shared.stateDidChange(.connecting)
+// startConectBle(model,autoJump: true)
+
let model = DeviceVM.shared.dataList[indexPath.row]
- if BleManager.shared.isConected(mac: model.mac) {
- App.shared.goToPage(HomeVC(device: model))
- return
+ if !BleManager.shared.isConected(mac: model.mac) {
+ startConectBle(model,autoJump: false)
}
- ConnectPopView.shared.stateDidChange(.connecting)
- startConectBle(model,autoJump: true)
+ App.shared.goToPage(HomeVC(device: model))
+
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView{
let header = HomeHeadInfoView.header(with: collectionView, indexPath: indexPath)
bar.startAnimating {[weak self] in
guard let self = self else{return}
// toolBar.recordBtn.stopCli()
+ guard let path = recordFilePath else{return}
let v = PopTextField()
v.show()
v.cancelTap = {
}
- v.okTap = {
+ v.okTap = { [weak self] text in
+ guard let self = self else{return}
+ let model = RecordDetailModel()
+ model.type = .present
+ model.from = bar.leftItem.language
+ model.to = .english
+ model.name = text
+ model.path = path
+ model.duration = YLToos.getDuration(model.path)
+ model.origin = textView.text
+ model.translate = ""
+
+ App.shared.goToPage(RecordDetailVC(record: model))
}
}
}
leftItem.alpha = 1
rightItem.alpha = 1
finished?()
-
}
+ recordBtn.activeView.backgroundColor = .hexString("#F7F7F7")
}
@objc func recordBtnAction(){
if recordBtn.activeView.animating {
--- /dev/null
+//
+// CloudHistoryRecordVC.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/25.
+//
+
+
+import UIKit
+import MJRefresh
+class CloudHistoryRecordVC: BaseVC{
+ let tableView = UITableView(frame: .zero, style: .plain)
+ let vm = HistoryRecordVM()
+ var list = [RecordHistoryModel]()
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ // Do any additional setup after loading the view.
+ }
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ tableView.reloadData()
+ }
+ override func setupViews() {
+ navBar.do { v in
+ v.title = "云存储空间"
+ let items = [NavigationRightItem(image: UIImage(named: "filter"),target: self, action: #selector(filterAction)),NavigationRightItem(image: UIImage(named: "search"), target: self,action: #selector(searchAction))]
+ v.setupRightViews(items)
+ }
+
+ tableView.do { v in
+ v.backgroundColor = .rgb(0xF7F7F7)
+ v.delegate = self
+ v.dataSource = self
+ v.estimatedRowHeight = 84
+ v.separatorStyle = .none
+ v.register(HistoryRecordCell.self, forCellReuseIdentifier: HistoryRecordCell.reuseID)
+ v.mj_header = MJRefreshNormalHeader(refreshingTarget: self, refreshingAction: #selector(refreshAction))
+ v.mj_footer = MJRefreshBackNormalFooter(refreshingTarget: self, refreshingAction: #selector(loadMoreAction))
+ }
+ view.addSubviews([tableView])
+ }
+ override func setupLayout() {
+ tableView.snp.makeConstraints { make in
+ make.left.right.equalToSuperview()
+ make.top.equalTo(kNavBtm)
+ make.bottom.equalToSuperview()
+ }
+ }
+ override func setupData() {
+ refreshAction()
+ }
+ @objc func searchAction(){
+
+ }
+ @objc func filterAction(){
+ let list = FiltterRecordType.alls.map({$0.title})
+ let v = CustomPicker(title: "筛选录音", list:list )
+ v.selectedIndex = list.firstIndex(where: {vm.type.title == $0})!
+ v.show()
+ v.didSelected = {[weak self] (index,value) in
+ guard let self = self else { return }
+ vm.type = FiltterRecordType.alls.first(where: {$0.title == value})!
+ tableView.mj_header?.beginRefreshing()
+ }
+ }
+ @objc func refreshAction(){
+ vm.refresh {[weak self] result in
+ guard let self = self else {return}
+ tableView.mj_header?.endRefreshing()
+ if result.success{
+ tableView.reloadData()
+ }
+
+ if result.success,result.data.hasNext == false{
+ tableView.mj_footer?.endRefreshingWithNoMoreData()
+ }
+ else{
+ tableView.mj_footer?.endRefreshing()
+ }
+ }
+ }
+ @objc func loadMoreAction(){
+ vm.loadMore {[weak self] result in
+ guard let self = self else {return}
+ if result.success{
+ tableView.reloadData()
+ }
+ }
+ }
+}
+
+extension CloudHistoryRecordVC:UITableViewDelegate,UITableViewDataSource {
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return vm.list.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = HistoryRecordCell.cell(withTableView: tableView, indexPath: indexPath)
+ cell.model = vm.list[indexPath.row]
+ return cell
+ }
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ let data = vm.list[indexPath.row]
+ let vc = RecordDetailVC(remoteData: data)
+ vc.delegateCallback = {[weak self] in
+ guard let self = self else{return}
+ vm.list.removeAll(where: {data === $0})
+ tableView.reloadData()
+ }
+ App.shared.goToPage(vc)
+// let api = CommomApi.getVoiceRecord(recordId: data.id)
+// HttpClient.request(api) {[weak self] (result:RecordHistoryDetailRoot,res) in
+// guard let self = self else {return}
+// if result.isSuccess{
+// let model = RecordDetailModel()
+// model.type = .translate
+// model.origin = result.data.summary
+// model.translate = ""
+// model.path = result.data.fileId
+// model.name = result.data.name
+// App.shared.goToPage(RecordDetailVC(record: model))
+// }
+// }
+
+
+ }
+ // 实现滑动删除功能
+ func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
+ if editingStyle == .delete {
+ // 从数据源中移除对应数据
+ vm.list.remove(at: indexPath.row)
+ // 从表格中删除对应行
+ tableView.deleteRows(at: [indexPath], with:.fade)
+ }
+ }
+
+ // 允许编辑
+ func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
+ return true
+ }
+}
--- /dev/null
+//
+// FileSaver.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/27.
+//
+
+import ZipArchive
+
+class FileSaver {
+ /// 获取文档目录的URL
+ private static func getDocumentsDirectory() -> URL {
+ let paths = FileManager.default.urls(for:.cachesDirectory, in:.userDomainMask)
+ return paths[0]
+ }
+
+ /// 将字符串保存为txt文件
+ /// - Parameters:
+ /// - string: 要保存的字符串
+ /// - fileName: 文件名(不包含扩展名)
+ /// - Returns: 是否保存成功
+ static func saveStringAsTxt(_ string: String) -> String? {
+ let fileURL = getDocumentsDirectory().appendingPathComponent("\(Date().format(.full6))").appendingPathExtension("txt")
+ do {
+ try string.write(to: fileURL, atomically: true, encoding:.utf8)
+ return fileURL.path
+ } catch {
+ Logger.debug("Error saving file: \(error)")
+ return nil
+ }
+ }
+}
+
+
+extension FileSaver{
+ static func zipFiles(files: [String]) -> String? {
+ let zipArchive = ZipArchive()
+ let des = getDocumentsDirectory().appendingPathComponent("\(Date().format(.full5))").appendingPathExtension("zip").path
+ if zipArchive.createZipFile2(des) {
+ for fileURL in files {
+
+ if !zipArchive.addFile(toZip: fileURL, newname: URL(fileURLWithPath: fileURL).lastPathComponent ) {
+ Logger.debug("Failed to add file: \(fileURL)")
+ zipArchive.closeZipFile2()
+ return nil
+ }
+ }
+ zipArchive.closeZipFile2()
+ Logger.debug("\(des)")
+ return des
+ } else {
+ Logger.debug("Failed to create zip file")
+ return nil
+ }
+ }
+}
+
class HistoryFontVC: BaseVC{
let tableView = UITableView(frame: .zero, style: .plain)
var list:[FontType] = [.min,.stand,.big]
- var currentType = FontType.stand
+ var currentType = FontCache.getFont()
let btn = CustomButton()
override func viewDidLoad() {
}
}
@objc func btnAction(){
-
+ FontCache.saveFont(type: currentType)
+ self.navigationController?.popViewController(animated: true)
}
}
let dateLabel = UILabel()
let typeLabel = UILabel()
-// var type:MineCellType = .user{
-// didSet{
-// titleLabel.text = type.title
-// }
-// }
+ var model:RecordHistoryModel?{
+ didSet{
+ guard let model = model else { return }
+ titleLabel.text = model.name
+ dateLabel.text = model.createTime
+ typeLabel.text = model.type.title
+ durationLabel.text = YLToos.formatSeconds(model.duration)
+ collectionIcon.image = UIImage(named: model.favorite == "0" ? "collection_normal":"collection_selected")
+ }
+ }
+ var localModel:RecordDetailModel?{
+ didSet{
+ guard let localModel = localModel else { return }
+ titleLabel.text = localModel.name
+ dateLabel.text = localModel.createTime
+ typeLabel.text = localModel.type.title
+ durationLabel.text = YLToos.formatSeconds(localModel.duration)
+ collectionIcon.image = UIImage(named: localModel.favorite == "0" ? "collection_normal":"collection_selected")
+ }
+ }
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
v.textAlignment = .left
v.text = "2025-06-02 10:28"
}
- collectionIcon.image = UIImage(named: "collection_selected")
+ collectionIcon.do { v in
+ v.yc.addTap(target: self, action: #selector(collectionAction))
+ }
playIcon.do { v in
- v.image = UIImage(named: "play_icon")
+ v.image = UIImage(named: "record_play 2")
}
}
}
playIcon.snp.makeConstraints { (m) in
- m.width.size.equalTo(34)
+ m.width.size.equalTo(30)
m.left.equalToSuperview().inset(14)
m.centerY.equalToSuperview()
}
m.right.equalTo(typeLabel)
}
}
+ @objc func collectionAction(){
+ if let model = model {
+ model.favorite = model.favorite == "0" ? "1":"0"
+ collectionIcon.image = UIImage(named: model.favorite == "0" ? "collection_normal":"collection_selected")
+
+ var params:[String:Any] = [:]
+ params["recordId"] = model.id
+ params["favorite"] = model.favorite
+ let api = CommomApi.voiceRecordCollection(param: params)
+ HttpClient.request(api) { (model:RecordHistoryModelRoot,res) in
+ }
+ }
+ else if let localModel = localModel{
+ localModel.favorite = localModel.favorite == "0" ? "1":"0"
+ collectionIcon.image = UIImage(named: localModel.favorite == "0" ? "collection_normal":"collection_selected")
+ RecordCache.shared.add(localModel)
+ }
+ }
}
var currentType = ShareType.audio_document
let btn = CustomButton()
+ let recordModel:RecordDetailModel
+
+ init(record model: RecordDetailModel,fileId:String?) {
+ self.recordModel = model
+ super.init()
+ if let id = fileId {
+ loadFile(filedId: id)
+ }
+ }
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
view.addSubviews([tableView,btn])
- btn.set(title: "设置", target: self, action: #selector(btnAction))
+ btn.set(title: "导出", target: self, action: #selector(btnAction))
}
override func setupLayout() {
tableView.snp.makeConstraints { make in
make.bottom.equalToSuperview().inset(82)
}
}
+
+ override func setupData() {
+
+ }
+ func loadFile(filedId id:String){
+ let api = CommomApi.recordUrl(filedId: id)
+ HttpClient.request(api) {[weak self] (model:CommonDataModel,res) in
+ guard let self = self else {return}
+ if model.isSuccess{
+ startDownload(url: model.data)
+ }
+ }
+ }
+ func startDownload(url:String){
+ // let url = "https://dc-cloud-priv.tos-cn-guangzhou.volces.com/music-file/2025_10_09/1976135290430767105.mp3"
+ HttpClient.download(url: url,type: "wav"){[weak self] result in
+ guard let self = self else {return}
+ if let path = result{
+ recordModel.path = path
+ }
+ }
+ }
+
@objc func btnAction(){
+ if currentType == .audio {
+ if recordModel.path.isNotEmpty {
+ saveFile(filePath: recordModel.path)
+ }
+
+ }
+ else if currentType == .document{
+ guard let path = FileSaver.saveStringAsTxt(recordModel.origin) else {
+ return
+ }
+ saveFile(filePath: path)
+ }
+ else{
+
+ guard let orginPath = FileSaver.saveStringAsTxt(recordModel.origin) else {
+ return
+ }
+ var list = [orginPath]
+ if recordModel.path.isNotEmpty {
+ list.append(recordModel.path)
+ }
+
+ if recordModel.translate.count > 0,let path = FileSaver.saveStringAsTxt(recordModel.translate) {
+ list.append(path)
+ }
+ if recordModel.summary.count > 0,let path = FileSaver.saveStringAsTxt(recordModel.summary) {
+ list.append(path)
+ }
+ guard let path = FileSaver.zipFiles(files: list) else { return }
+
+ saveFile(filePath: path)
+ }
}
}
+extension HistoryRecordShareVC:UIDocumentPickerDelegate{
+ //保存文件到手机文件指定目录
+ func saveFile(filePath:String) {
+ let fUrl = NSURL(fileURLWithPath: filePath)
+ let vc = UIDocumentPickerViewController(url: fUrl as URL, in: .exportToService);
+ vc.delegate = self
+ vc.modalPresentationStyle = .overFullScreen
+ self.present(vc, animated: true)
+ }
+ public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
+ controller.dismiss(animated: true)
+ }
+}
extension HistoryRecordShareVC:UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
import UIKit
class HistoryRecordVC: BaseVC{
let tableView = UITableView(frame: .zero, style: .plain)
- let bottomView = HistoryBottonView()
- var list = [1,2,3,4,5,6,7,8]
+// let bottomView = HistoryBottonView()
+ var list = [RecordDetailModel]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ tableView.reloadData()
+ }
override func setupViews() {
navBar.do { v in
v.title = "历史录音"
v.separatorStyle = .none
v.register(HistoryRecordCell.self, forCellReuseIdentifier: HistoryRecordCell.reuseID)
}
- view.addSubviews([tableView,bottomView])
+ view.addSubviews([tableView])
}
override func setupLayout() {
- bottomView.snp.makeConstraints { make in
- make.left.right.bottom.equalToSuperview()
- }
+// bottomView.snp.makeConstraints { make in
+// make.left.right.bottom.equalToSuperview()
+// }
tableView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalTo(kNavBtm)
- make.bottom.equalTo(bottomView.snp.top)
+ make.bottom.equalToSuperview()
}
}
+ override func setupData() {
+ list = RecordCache.shared.getList()
+ tableView.reloadData()
+ }
@objc func searchAction(){
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = HistoryRecordCell.cell(withTableView: tableView, indexPath: indexPath)
-// cell.type = list[indexPath.row]
+ cell.localModel = list[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let data = list[indexPath.row]
-
+ App.shared.goToPage(RecordDetailVC(record: data,needFrontVC:true))
}
// 实现滑动删除功能
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
--- /dev/null
+//
+// HistoryRecordVM.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/25.
+//
+
+class HistoryRecordVM:BaseVM{
+ var list = [RecordHistoryModel]()
+ var page = 0
+ var type:FiltterRecordType = .all
+ var keyword:String?
+ var date = ""
+
+
+ public func refresh(completion:@escaping (_ result:RecordHistoryModelRoot) ->Void) {
+ self.page = 1
+ request(completion: completion)
+ }
+ public func loadMore(completion:@escaping (_ result:RecordHistoryModelRoot) ->Void) {
+ self.page += 1
+ request(completion: completion)
+ }
+ func request(completion:@escaping (_ result:RecordHistoryModelRoot) ->Void) {
+ var params:[String:Any] = [:]
+ params["page"] = page
+ params["date"] = ""
+ if type == .all {
+ params["type"] = ""
+ }
+ else if type == .colletion{
+ params["favorite"] = "1"
+ }
+ else{
+ params["type"] = type.rawValue
+ }
+ if let keyword = keyword {
+ params["keyword"] = keyword
+ }
+ let api = CommomApi.voiceRecordList(param: params)
+ HttpClient.request(api) {[weak self] (model:RecordHistoryModelRoot,res) in
+ guard let self = self else {return}
+ if model.isSuccess{
+ page = model.data.currentPage
+ if model.data.currentPage == 1 {
+ list = model.data.list
+ }
+ else{
+ list += model.data.list
+ }
+ }
+ completion(model)
+ }
+ }
+}
--- /dev/null
+//
+// RecordHistoryModel.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/25.
+//
+
+import HandyJSON
+
+class RecordHistoryDetailRoot:ResponseBaseModel {
+ var data = RecordHistoryModel()
+}
+
+
+class RecordHistoryModelRoot:ResponseBaseModel {
+ var data = RecordHistoryModelData()
+}
+class RecordHistoryModelData:HandyJSON {
+ var list = [RecordHistoryModel]()
+ var total = 0
+ var pageSize = 0
+ var currentPage = 0
+ var totalPage = 0
+ var hasNext = false
+ var hasPre = false
+
+ required public init() { }
+}
+
+class RecordHistoryModel:HandyJSON{
+ var type:RecordType = .present
+ var id = ""
+ var name = ""
+ var duration = 0
+
+ var favorite = "0"//0不收藏,1收藏
+ var fileId = ""
+ var summary = ""
+
+ var createTime = ""
+ var updateTime = ""
+ required public init() { }
+}
enum FontType:Int{
- case min
- case stand
- case big
+ case min = 10
+ case stand = 14
+ case big = 18
var title:String{
switch self {
case .min:
return "大"
}
}
+ var font:UIFont{
+ return .regular(CGFloat(self.rawValue))
+ }
+// var value:Int{
+// switch self {
+// case .min:
+// return 10
+// case .stand:
+// return 14
+// case .big:
+// return 18
+// }
+// }
}
enum ShareType:Int{
let titleLabel = UILabel()
let btn = UIButton(type: .custom)
let textView = UITextView()
- var title:String!{
+ var title:String! = ""{
didSet{
titleLabel.text = title
}
}
- var content:String!{
+ var content:String! = ""{
didSet{
textView.text = content
}
v.addTarget(self, action: #selector(copyAction), for: .touchUpInside)
}
textView.do { v in
- v.font = .regular(14)
v.text = ""
v.textColor = .hexString("#121212")
v.contentInset = UIEdgeInsets(top: 0, left: 18, bottom: 0, right: 18)
import UIKit
import JoyGemAI
import AVFAudio
+import AVFoundation
+
+
class RecordDetailVC:BaseVC{
let timeLabel = UILabel()
let topBar = RecordDetailTopBar()
let originView = RecordDetaiContent()
let translateView = RecordDetaiContent()
let summaryView = RecordDetaiContent()
+ var data:RecordDetailModel?
+ var remoteData:RecordHistoryModel?
+ var needFrontVC = false
+ var delegateCallback:(()->Void)?
+
+ init(record model: RecordDetailModel,needFrontVC:Bool = false) {
+ self.data = model
+ self.needFrontVC = needFrontVC
+ super.init()
+ }
+ init(remoteData data: RecordHistoryModel) {
+ self.remoteData = data
+ self.needFrontVC = true
+ super.init()
+ }
override func viewDidLoad() {
super.viewDidLoad()
+ if let data = data {
+ setupViews(data:data)
+ }
+ if let data = remoteData {
+ loadData(data: data)
+ }
}
- override func setupViews() {
- navBar.title = "现场录音"
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ originView.textView.font = FontCache.getFont().font
+ translateView.textView.font = FontCache.getFont().font
+ summaryView.textView.font = FontCache.getFont().font
+ }
+ override func viewDidAppear(_ animated: Bool) {
+ super.viewDidAppear(animated)
+ if needFrontVC == false {
+ var list = self.navigationController!.viewControllers
+ list.remove(at: list.count - 2)
+ self.navigationController!.viewControllers = list
+ }
+ }
+ override func viewWillDisappear(_ animated: Bool) {
+ super.viewWillDisappear(animated)
+ if remoteData == nil,let localData = data {
+ RecordCache.shared.add(localData)
+ }
+ }
+ func setupViews(data:RecordDetailModel) {
+ navBar.title = data.type.title
navBar.rightView.setImage(UIImage(named: "upload"), for: .normal)
+ if remoteData == nil{
+ navBar.rightView.isHidden = false
+ }
+ else{
+ navBar.rightView.isHidden = true
+ }
toolBar.delegate = self
topBar.do { v in
v.font = .regular(14)
v.textAlignment = .center
v.textColor = .hexString("#666666")
- v.text = Date().format(.full3)
+ v.text = data.createTime
}
originView.do { v in
v.title = "原文"
-// v.content = "好优美的一篇文章,山花落尽,我心犹青|||记得春日时分,山花绽放得那样热烈,鲜红的、明黄的、洁白的,仿佛将整片山野染成了一幅画。那时的心也如山花般明亮,轻快地跳跃在生活的每一个角落。"
+ v.content = data.origin
}
translateView.do { v in
v.title = "译文"
-// v.content = "What a beautiful article, the mountain flowers have all fallen, yet my heart remains green ||| Remembering the springtime, the mountain flowers bloomed so vividly, bright red, bright yellow, and pure white, as if they had painted the entire mountain wilderness into a picture. At that time, my heart was as bright as the mountain flowers, joyfully jumping around in every corner of life. "
+ v.content = data.translate
}
summaryView.do { v in
v.title = "摘要"
-// v.content = "这是摘要"
+ v.content = data.summary
}
view.addSubviews([timeLabel,topBar,originView,translateView,summaryView,toolBar])
- }
- override func setupLayout() {
timeLabel.snp.makeConstraints { make in
make.width.centerX.equalToSuperview()
make.height.equalTo(36)
}
updateLayout()
}
- override func setupData() {
- }
override func navRightViewTapped() {
-
+ CustomAlert.showWith(title: "云同步", messgage: "是否上传运存储空间备份?", cancelCallback: {}) {[weak self] in
+ self?.uploadToServer()
+ }
}
func updateLayout(){
translateView.isHidden = true
summaryView.isHidden = true
}
-
-
+ }
+ func loadData(data:RecordHistoryModel){
+ YLprogressHUD.showLoading()
+ let api = CommomApi.getVoiceRecord(recordId: data.id)
+ HttpClient.request(api) {[weak self] (result:RecordHistoryDetailRoot,res) in
+ guard let self = self else {return}
+ if result.isSuccess{
+ YLprogressHUD.hidden()
+ let model = RecordDetailModel()
+ model.type = result.data.type
+ model.origin = result.data.summary
+ model.translate = ""
+ model.path = result.data.fileId
+ model.name = result.data.name
+ model.createTime = result.data.createTime
+ self.data = model
+ setupViews(data: model)
+ }
+ else{
+ YLprogressHUD.showAutoHiden("请求失败")
+ }
+ }
}
}
extension RecordDetailVC:RecordDetailTopBarDelegate{
func recordDetailTopBarSummaryAction(_ bar: RecordDetailTopBar) {
updateLayout()
+ if let data = data,data.summary.isEmpty {
+ summaryAction()
+ }
}
func recordDetailBarTranstlateAction(_ bar: RecordDetailTopBar) {
}
extension RecordDetailVC:RecordDetailBarDelegate{
func recordDetailBarTranstlateAction(_ bar: RecordDetailBar) {
+ var list = AiSupportLanguage.translate.map{$0.title}
+ list = list.filter { $0 != data!.from.title }
+ let v = CustomPicker(title: "请选择语言", list:list )
+ v.selectedIndex = list.firstIndex(where: {data!.to.title == $0})!
+ v.show()
+ v.didSelected = {[weak self] (index,value) in
+ guard let self = self else { return }
+ data!.to = AiSupportLanguage.translate.first(where: {$0.title == value})!
+ translateAction()
+ }
}
func recordDetailBarRenameAction(_ bar: RecordDetailBar) {
-
+ let v = PopTextField()
+ v.textFiled.text = data?.name ?? ""
+ v.cancelButton.setTitle("取消", for: .normal)
+ v.show()
+ v.cancelTap = {
+
+ }
+ v.okTap = { [weak self] text in
+ guard let self = self else{return}
+ data!.name = text
+ if let data = remoteData{
+ data.name = text
+ renameAction(data)
+ }
+ }
}
func recordDetailBarPlayAction(_ bar: RecordDetailBar) {
-
+ if let data = remoteData{
+ PopPlayView(filePath: nil,fieldId: data.fileId, duration: data.duration).show()
+ }
+ else if let data = data {
+ PopPlayView(filePath: data.path, fieldId: nil,duration: data.duration).show()
+ }
}
func recordDetailBarMoreAction(_ bar: RecordDetailBar) {
+ let v = PopMenu()
+ v.show()
+ v.shareCallback = {[weak self] in
+ guard let self = self else {
+ return
+ }
+ guard let data = data else {
+ return
+ }
+ App.shared.goToPage(HistoryRecordShareVC(record: data,fileId: remoteData?.fileId))
+ }
+ v.fontCallback = {[weak self] in
+ guard let self = self else {
+ return
+ }
+ App.shared.goToPage(HistoryFontVC())
+ }
+ v.deleteCallback = {[weak self] in
+ guard let self = self else {
+ return
+ }
+ CustomAlert.showWith(title: "提示", messgage: "确定要删除选中的项目吗?", cancelCallback: {}) {
+ if let data = self.remoteData{
+ let api = CommomApi.deleteVoiceRecord(recordId: data.id)
+ HttpClient.request(api) {(model:ResponseBaseModel,res) in
+ self.delegateCallback?()
+ App.shared.popPage()
+ }
+ }
+ else{
+ self.delegateCallback?()
+ App.shared.popPage()
+ }
+ }
+ }
+ }
+}
+
+extension RecordDetailVC{
+ func renameAction(_ data:RecordHistoryModel){
+ var params:[String:Any] = [:]
+ params["id"] = data.id
+ params["name"] = data.name
+
+ let api = CommomApi.updateVoiceRecord(param: params)
+ HttpClient.request(api) {(model:ResponseBaseModel,res) in
+
+ }
+ }
+ func translateAction(){
+ translateView.content = ""
+ JoyGemAIManager.shared().cancelTranslateRequest()
+
+ JoyGemAIManager.shared().translate(originView.content, from: data!.from.value, to: data!.to.value) {[weak self] text, finish in
+ guard let self = self else{return}
+ translateView.content += text
+ if (finish) {
+ data!.translate = translateView.content
+ }
+ } error: {[weak self] error in
+ guard let self = self else{return}
+ }
+ }
+ func summaryAction(){
+ summaryView.content = ""
+ JoyGemAIManager.shared().cancelTranslateRequest()
+ JoyGemAIManager.shared().summary(originView.content) {[weak self] text, finish in
+ guard let self = self else{return}
+ summaryView.content += text
+ if (finish) {
+ data!.summary = summaryView.content
+ }
+ } error: {[weak self] error in
+ guard let self = self else{return}
+ }
+ }
+ func uploadToServer(){
+ YLprogressHUD.showLoading()
+ startUploadFile(data!.path) {[weak self] fileId in
+ guard let self = self else{return}
+ guard let fid = fileId else{
+ YLprogressHUD.showAutoHiden("请求失败")
+ return
+ }
+ commitToServer(fid)
+ }
+
+ }
+ func commitToServer(_ fileId:String){
+ var params:[String:Any] = [:]
+ params["name"] = data!.name
+ params["type"] = data!.type.rawValue
+ params["favorite"] = "0"
+ params["duration"] = YLToos.getDuration(data!.path)
+ params["fileId"] = fileId
+ params["summary"] = data!.origin
+ Logger.debug(params)
+ HttpClient.request(.voiceRecord(param: params)) {(model:AppUpdateModelRoot,res) in
+ YLprogressHUD.hidden()
+ if model.isSuccess{
+// App.shared.popToPage(num: 2)
+ YLprogressHUD.showAutoHiden("请求成功")
+ }
+ else{
+ YLprogressHUD.showAutoHiden(model.msg)
+ }
+ }
+ }
+
+ func startUploadFile(_ path:String,finished:@escaping ((String?) -> Void)){
+ let url = URL(fileURLWithPath: path)
+ var params:[String:Any] = [:]
+ params["fileUrl"] = url
+ let api = CommomApi.uploadVoiceFile(param: params)
+ HttpClient.uploadVoiceFile(api){(model:CommonDataModel, res) in
+ if model.isSuccess{
+ finished(model.data)
+ }
+ else{
+ finished(nil)
+ }
+ }
}
}
+
JoyGemSIManager.shared().stop()
bar.startAnimating {[weak self] in
guard let self = self else{return}
- // toolBar.recordBtn.stopCli()
+ guard let path = recordFilePath else{return}
let v = PopTextField()
v.show()
v.cancelTap = {
}
- v.okTap = {
+ v.okTap = { [weak self] text in
+ guard let self = self else{return}
+ let model = RecordDetailModel()
+ model.type = .translate
+ model.from = bar.leftItem.language
+ model.to = .english
+ model.name = text
+ model.path = path
+ model.duration = YLToos.getDuration(model.path)
+ model.origin = textView.text ?? ""
+ model.translate = translateTextView.text ?? ""
+ App.shared.goToPage(RecordDetailVC(record: model))
}
}
}
imageView.do { v in
//v.backgroundColor = .lightGray
// v.image = UIImage(named: "home_header")
+
+
}
+ NotificationManager.add(self, selector: #selector(deviceChange(_:)), forName: .deviceValidChange)
+ updateUI()
}
override func setupLayout() {
make.bottom.equalToSuperview()
}
}
+ @objc func deviceChange(_ noti:Notification){
+ updateUI()
+ }
+ func updateUI(){
+ if let device = DeviceVM.shared.currentDevice{
+ imageView.kf.setImage(with: device.image.yc.asUrl)
+
+ if BleManager.shared.isConnetd {
+ alpha = 1
+ }
+ else{
+ alpha = 0.3
+ }
+ }
+
+ }
}
make.top.equalTo(functionView.snp.bottom).offset(10)
make.left.equalToSuperview()
make.width.equalTo(kScreenWid)
- make.bottom.equalToSuperview()
+ make.bottom.equalToSuperview().inset(10)
}
}
class DeviceVM:BaseVM{
static let shared = DeviceVM()
var dataList = [HomeDeviceModel]()
+
+ var currentDevice:HomeDeviceModel?{
+ for item in dataList {
+ if let device = BleManager.shared.connectPeripheral,device.mac == item.mac {
+ return item
+ }
+ }
+ return dataList.first
+ }
public func refresh(completion:@escaping (_ result:HomeDeviceModelRoot) ->Void) {
let api = CommomApi.deviceList
BleManager.shared.cancel()
return
}
- // getMac {[weak self] mac in
- // guard let self = self else {return}
- // guard let mac = mac,let mac1 = formatStringAsMacAddress(mac) else{
- // BleManager.shared.cancel()
- // self.showError()
- // return
- // }
- // getDN {[weak self] dn in
- // guard let self = self else {return}
- // guard let deviceName = dn else{
- // BleManager.shared.cancel()
- // self.showError()
- // return
- // }
- //
- // startBind(dn: deviceName, mac: mac1, prodName: prodName)
- // }
- // }
getDN { dn in
guard let deviceName = dn else{
BleManager.shared.cancel()
}
}
static func getDN(finished:@escaping ((_ mac:String?)->Void)) {
- finished("EEBD03250F66")
- // JoyGemAIManager.shared().device.macAddress { edr, ble in
- // Logger.debug("edr:\(edr),ble:\(ble)");
- // finished(ble)
- // } error: { error in
- // Logger.debug("\(error!.localizedDescription)")
- // finished(nil)
- // }
+ JoyGemAIManager.shared().device.getDN { deviceName in
+ finished(deviceName)
+ } error: { error in
+ Logger.debug("\(error!.localizedDescription)")
+ finished(nil)
+ }
}
static func getVersion(finished:@escaping ((_ version:String?)->Void)) {
JoyGemAIManager.shared().device.software { version in
import Foundation
import JoyGemAI
-enum AiSupportLanguage{
- case chinse
- case english
- case japanese
- case korean
- case french
- case spanish
- case portuguese
- case indonesian
- case russian
- case malay
+enum AiSupportLanguage:String{
+ case chinse = "chinse"
+ case english = "english"
+ case japanese = "japanese"
+ case korean = "korean"
+ case french = "french"
+ case spanish = "spanish"
+ case portuguese = "portuguese"
+ case indonesian = "indonesian"
+ case russian = "russian"
+ case malay = "malay"
- /// 现场录音,通话录音,同声传译
+ /// 现场录音,通话录音,同传听译
static var record:[AiSupportLanguage]{
return [.chinse,.english,.japanese,.korean]
}
//现场录音 中,英,日,韩
//通话录音 中,英,日,韩
//双耳互译 中英
-//同声传译 中,英,日,韩
+//同传听译 中,英,日,韩
//面对面翻译 中,英,日
//文本翻译 中、英、日、韩、法、西班牙、葡萄牙、印度尼西亚、俄文、马来文
// BleManager.shared.startScanDevice()
// App.shared.enter()
// }
+
+// let model = RecordDetailModel()
+// model.type = .callingRecord
+// model.origin = "深圳今天下雨吗?明天下雨吗,后天下雨吗,未来一周下雨吗"
+// model.translate = ""
+// model.path = ""
+// model.name = ""
+// App.shared.goToPage(RecordDetailVC(record: model))
}
}
viewController.hidesBottomBarWhenPushed = true
topVC().navigationController?.pushViewController(viewController, animated: animated)
}
- func popPage(){
- topVC().navigationController?.popViewController(animated: true)
+ func popPage(animated:Bool = true){
+ topVC().navigationController?.popViewController(animated: animated)
}
func popToViewController(_ vc:UIViewController){
let vcs = topVC().navigationController?.viewControllers ?? []
// DB209A55-DD0E-5031-29FA-40D734C34971
// "edr:21140DE4C3D9"
// "ble:21140D2CC682"
- if peripheral.identifier.uuidString != "DB209A55-DD0E-5031-29FA-40D734C34971" {
- return
- }
+// if peripheral.identifier.uuidString != "DB209A55-DD0E-5031-29FA-40D734C34971" {
+// return
+// }
let mac = getMac(advertisementData) ?? ""
devices.append(DCPeripheral(device: peripheral,mac: mac))
Logger.debug(peripheral)
let tableView = UITableView(frame: .zero, style: .plain)
var list:[MyDeviceListCellModel] = []
var model:HomeDeviceModel
-
+ private let footerView = FooterView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 200))
init(device: HomeDeviceModel) {
model = device
list = [
v.separatorStyle = .none
v.register(MyDeviceInfoCell.self, forCellReuseIdentifier: MyDeviceInfoCell.reuseID)
v.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: kScreenHei, height: 20))
+ v.tableFooterView = footerView
v.bounces = false
}
+ footerView.deviceModel = model
view.addSubviews([tableView])
}
v.font = .regular(14)
v.textAlignment = .right
}
+
}
override func setupLayout() {
}
+fileprivate class FooterView: BaseView {
+ let btn = CustomButton()
+ var deviceModel:HomeDeviceModel!
+ override func setupViews() {
+ addSubviews([btn])
+
+ btn.set(title: "移除设备", style: .theme4,target: self, action: #selector(btnAction))
+
+ }
+ override func setupLayout() {
+ btn.snp.makeConstraints { make in
+ make.left.right.equalToSuperview().inset(52)
+ make.height.equalTo(46)
+ make.top.equalToSuperview().inset(40)
+ }
+
+ }
+ @objc func btnAction(){
+ CustomAlert.showWith(title: "提示", messgage: "确定要解绑该设备吗?", cancelCallback: {}) {[weak self] in
+ guard let self = self else{return}
+ unbindActon()
+ }
+ }
+ func unbindActon(){
+ YLprogressHUD.showLoading()
+ let api = CommomApi.unbind(deviceId: deviceModel.deviceId)
+ HttpClient.request(api) {[weak self] (model:HomeDeviceModelRoot,res) in
+ guard let self = self else {return}
+ if model.isSuccess{
+ YLprogressHUD.hidden()
+ DeviceVM.shared.dataList.removeAll(where: {$0.deviceId == self.deviceModel.deviceId})
+ BleManager.shared.cancel()
+ App.shared.popPage()
+ }
+ else{
+ YLprogressHUD.showAutoHiden(model.msg)
+ }
+ }
+ }
+
+}
}
view.addSubviews([tableView])
}
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ tableView.reloadData()
+ }
override func setupLayout() {
tableView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.bottom.equalToSuperview()
}
}
-
}
extension MyDeviceListVC:UITableViewDelegate,UITableViewDataSource {
textField.do { v in
v.textColor = .black
- v.keyboardType = .phonePad
+ v.keyboardType = .default
v.placeholder = "请输入密码"
v.isSecureTextEntry = true
}
import Kingfisher
class MineHeaderView: BaseView {
let userInfo = MineUserInfoView()
+ let cloud = CloudStorageView()
let banner = MineBannerView()
override func setupViews() {
- addSubviews([userInfo,banner])
+ addSubviews([userInfo,cloud,banner])
// let model1 = BannerModel()
// model1.imgPath = "mine_banner1"
m.left.right.equalToSuperview()
m.height.equalTo(100)
}
+ cloud.snp.makeConstraints { make in
+ make.top.equalTo(userInfo.snp.bottom).offset(15)
+ make.left.right.equalToSuperview().inset(18)
+ make.height.equalTo(46)
+ }
banner.snp.makeConstraints { (m) in
m.height.equalTo(126)
m.left.right.equalToSuperview()
- m.top.equalTo(userInfo.snp.bottom).offset(20)
+ m.top.equalTo(cloud.snp.bottom).offset(15)
}
}
}
App.shared.goToPage(MyDeviceListVC())
}
}
+class CloudStorageView: BaseView {
+ let bgView = UIView()
+ let icon = UIImageView()
+ let titleLabel = UILabel()
+ let nameLabel = UILabel()
+ let progressView = UIProgressView()
+ override func setupViews() {
+ addSubview(bgView)
+ bgView.addSubviews([icon,titleLabel,nameLabel,progressView])
+
+ bgView.do { v in
+ v.yc.setCornerRadius(12)
+ v.backgroundColor = .white
+ }
+ icon.do { v in
+ v.image = UIImage(named: "mine_cloud")
+ }
+ titleLabel.do { (v) in
+ v.textColor = .rgb(0x121212)
+ v.font = .bold(14)
+ v.textAlignment = .left
+ v.text = "0.2GB/1GB"
+ }
+ nameLabel.do { (v) in
+ v.textColor = .rgb(0x666666)
+ v.font = .regular(14)
+ v.textAlignment = .left
+ v.text = "云储存空间"
+ }
+ progressView.do { v in
+ v.yc.setCornerRadius(2)
+ }
+ yc.addTap(target: self, action: #selector(tapAction))
+ }
+
+ override func setupLayout() {
+ bgView.snp.makeConstraints { make in
+ make.left.right.equalToSuperview()
+ make.top.equalToSuperview()
+ make.bottom.equalToSuperview()
+ }
+ icon.snp.makeConstraints { (m) in
+ m.size.equalTo(34)
+ m.left.equalToSuperview().inset(14)
+ m.centerY.equalToSuperview()
+ }
+ titleLabel.snp.makeConstraints { (m) in
+ m.top.equalToSuperview().inset(6)
+ m.left.equalToSuperview().inset(54)
+ }
+ nameLabel.snp.makeConstraints { (m) in
+ m.centerY.equalTo(titleLabel)
+ m.right.equalToSuperview().inset(14)
+ }
+ progressView.snp.makeConstraints { make in
+ make.right.equalToSuperview().inset(14)
+ make.left.equalToSuperview().inset(54)
+ make.height.equalTo(6)
+ make.bottom.equalToSuperview().inset(8)
+ }
+// PopPlayView().show()
+ }
+
+ @objc func tapAction(){
+ App.shared.goToPage(CloudHistoryRecordVC())
+ }
+
+}
class MineVC: BaseVC{
let tableView = UITableView(frame: .zero, style: .plain)
let list:[MineCellType] = [.instructions,.update,.language,.more,.feeback,.about]
- let headerView = MineHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 266))
+ let headerView = MineHeaderView(frame: CGRect(x: 0, y: 0, width: kScreenWid, height: 317))
override func viewDidLoad() {
super.viewDidLoad()
}
}
}
+ NotificationManager.add(self, selector: #selector(deviceChange(_:)), forName: .deviceValidChange)
+ updateState()
+ }
+ @objc func deviceChange(_ noti:Notification){
+ updateState()
+ }
+ func updateState(){
+ if BleManager.shared.isConnetd {
+ alpha = 1
+ }
+ else{
+ alpha = 0.3
+ }
}
override func setupLayout() {
super.viewDidLoad()
}
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ headerView.updateUI()
+ }
override func setupViews() {
self.navBar.title = "模式"
}
}
findView.yc.addTap(target: self, action: #selector(findAction))
+ NotificationManager.add(self, selector: #selector(deviceChange(_:)), forName: .deviceValidChange)
+ updateState()
}
override func setupLayout() {
bgView.snp.makeConstraints { make in
}
extension ModeVC{
+ @objc func deviceChange(_ noti:Notification){
+ updateState()
+ }
+ func updateState(){
+ self.findView.alpha = BleManager.shared.isConnetd ? 1:0.3
+ }
+
func selectedModeAction(_ mode:JoyGemEQMode){
JoyGemAIManager.shared().device.setEQMode(mode) { err in
Logger.debug("setEQMode:\(err)");
let bgView = UIImageView()
let musicView = UIImageView()
- let slider = UISlider()
let nameLabel = UILabel()
- let titleLabel = UILabel()
- let valueLabel = UILabel()
+
+ let slider = UISlider()
+ let progressLabel = UILabel()
+ let durationLabel = UILabel()
let playBtn = UIButton(type: .custom)
let musicModel:MusicModel
override func setupViews() {
navBar.leftView.setImage(UIImage(named: "arrow_back_white"), for: .normal)
navBar.backgroundColor = .clear
- view.addSubviews([bgView,musicView,slider,nameLabel,titleLabel,valueLabel,playBtn])
+ view.addSubviews([bgView,musicView,slider,nameLabel,progressLabel,durationLabel,playBtn])
view.bringSubviewToFront(navBar)
v.textAlignment = .center
v.font = .medium(18)
}
- titleLabel.do { v in
+ progressLabel.do { v in
v.text = "00:00"
v.textColor = .white
v.textAlignment = .center
v.font = .regular(12)
}
- valueLabel.do { v in
+ durationLabel.do { v in
v.text = YLToos.formatSeconds1(musicModel.duration)
v.textColor = .white
v.textAlignment = .center
guard let self = self else {return}
slider.maximumValue = duration
slider.setValue(current, animated: true)
- titleLabel.text = YLToos.formatSeconds1(Int(current))
- valueLabel.text = YLToos.formatSeconds1(Int(duration))
+ progressLabel.text = YLToos.formatSeconds1(Int(current))
+ durationLabel.text = YLToos.formatSeconds1(Int(duration))
}
}
override func setupLayout() {
make.left.right.equalToSuperview().inset(40)
make.top.equalTo(musicView.snp.bottom).offset(100)
}
- titleLabel.snp.makeConstraints { make in
+ progressLabel.snp.makeConstraints { make in
make.left.equalTo(slider)
make.top.equalTo(slider.snp.bottom)
}
- valueLabel.snp.makeConstraints { make in
+ durationLabel.snp.makeConstraints { make in
make.right.equalTo(slider)
make.top.equalTo(slider.snp.bottom)
}
@objc func sliderChanged(_ slider:UISlider){
let value = YLToos.formatSeconds1(Int(slider.value))
Logger.debug(slider.value)
- if let text = titleLabel.text, text != value {
- titleLabel.text = value
+ if let text = progressLabel.text, text != value {
+ progressLabel.text = value
}
AudioPlayerManager.shared.setDuration(slider.value)
}
func startDownload(url:String,fileId:String){
// let url = "https://dc-cloud-priv.tos-cn-guangzhou.volces.com/music-file/2025_10_09/1976135290430767105.mp3"
- HttpClient.download(url: url,fileId: fileId){[weak self] filePath in
+ HttpClient.download(url: url,type: "mp3"){[weak self] filePath in
guard let self = self else {return}
if let path = filePath{
startPlay(path: path)
titleLab.font = .medium(16)
titleLab.text = "微光"
- imgV.image = UIImage(named: "sleep_demo")
+ imgV.do { v in
+ v.contentMode = .scaleAspectFill
+ v.clipsToBounds = true
+ }
playImgV.image = UIImage(named: "play_icon")
}
let encoder = NSKeyedArchiver.archivedData(withRootObject: deviceList)
userDefaults.set(encoder, forKey: deviceListKey)
+ userDefaults.synchronize()
}
func getDeviceList() -> [DeviceModel] {
--- /dev/null
+//
+// FontCache.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/24.
+//
+
+class FontCache{
+ static func saveFont(type:FontType){
+ UserDefaults.standard.set(type.rawValue, forKey: "FontCache")
+ UserDefaults.standard.synchronize()
+ }
+ static func getFont()->FontType{
+ if let value = UserDefaults.standard.value(forKey: "FontCache"),let font = value as? Int {
+ return FontType(rawValue: font) ?? .stand
+ }
+ return FontType.stand
+ }
+}
--- /dev/null
+//
+// RecordCache.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/24.
+//
+
+class RecordCache {
+ static let shared = RecordCache()
+ private let userDefaults = UserDefaults.standard
+ private let deviceListKey = "deviceListKey"
+
+ func add(_ device: RecordDetailModel) {
+ var deviceList = getList()
+ if let index = deviceList.firstIndex(where: { $0.createTime == device.createTime }) {
+ deviceList[index] = device
+ }
+ else{
+ deviceList.append(device)
+ }
+ let encoder = NSKeyedArchiver.archivedData(withRootObject: deviceList)
+ userDefaults.set(encoder, forKey: deviceListKey)
+ userDefaults.synchronize()
+ }
+ func remove(_ device: RecordDetailModel) {
+ var deviceList = getList()
+ if let index = deviceList.firstIndex(where: { $0.createTime == device.createTime }) {
+ deviceList.remove(at: index)
+ }
+
+ let encoder = NSKeyedArchiver.archivedData(withRootObject: deviceList)
+ userDefaults.set(encoder, forKey: deviceListKey)
+ userDefaults.synchronize()
+ }
+
+ func getList() -> [RecordDetailModel] {
+ if let data = userDefaults.data(forKey: deviceListKey),
+ let deviceList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [RecordDetailModel] {
+ return deviceList
+ }
+ return []
+ }
+}
--- /dev/null
+//
+// RecordDetailModel.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/23.
+//
+import HandyJSON
+
+enum FiltterRecordType:String,HandyJSONEnum{
+ case present = "present"
+ case phone = "phone"
+ case translate = "translate"
+ case all = "all"
+ case colletion = "colletion"
+
+ var title:String{
+ switch self {
+ case .present:
+ return "现场录音"
+ case .phone:
+ return "通话录音"
+ case .translate:
+ return "同传听译"
+ case .all:
+ return "全部录音"
+ case .colletion:
+ return "收藏录音"
+ }
+ }
+ static var alls:[FiltterRecordType]{
+ return [.all,.colletion,.present,.phone,.translate]
+ }
+}
+
+enum RecordType:String,HandyJSONEnum{
+ case present = "present"
+ case phone = "phone"
+ case translate = "translate"
+
+ var title:String{
+ switch self {
+ case .present:
+ return "现场录音"
+ case .phone:
+ return "通话录音"
+ case .translate:
+ return "同传听译"
+ }
+ }
+}
+
+class RecordDetailModel:NSObject, NSCoding{
+ func encode(with coder: NSCoder) {
+ coder.encode(from.rawValue, forKey: "from")
+ coder.encode(to.rawValue, forKey: "to")
+ coder.encode(type.rawValue, forKey: "type")
+ coder.encode(origin, forKey: "origin")
+ coder.encode(translate, forKey: "translate")
+ coder.encode(summary, forKey: "summary")
+ coder.encode(path, forKey: "path")
+ coder.encode(name, forKey: "name")
+ coder.encode("\(duration)", forKey: "duration")
+ coder.encode(createTime, forKey: "createTime")
+ coder.encode(favorite, forKey: "favorite")
+ }
+ override init() {
+ createTime = Date().format(.full)
+ }
+
+ required init?(coder: NSCoder) {
+ from = AiSupportLanguage(rawValue: coder.decodeObject(forKey: "from") as! String) ?? .chinse
+ to = AiSupportLanguage(rawValue: coder.decodeObject(forKey: "to") as! String) ?? .english
+ type = RecordType(rawValue: coder.decodeObject(forKey: "type") as! String) ?? .present
+ origin = coder.decodeObject(forKey: "origin") as? String ?? ""
+ translate = coder.decodeObject(forKey: "translate") as? String ?? ""
+ summary = coder.decodeObject(forKey: "summary") as? String ?? ""
+ path = coder.decodeObject(forKey: "path") as? String ?? ""
+ name = coder.decodeObject(forKey: "name") as? String ?? ""
+ duration = Int(coder.decodeObject(forKey: "duration") as! String) ?? 0
+ createTime = coder.decodeObject(forKey: "createTime") as? String ?? ""
+ favorite = coder.decodeObject(forKey: "favorite") as? String ?? ""
+ }
+ var type:RecordType = .present
+ var from:AiSupportLanguage = .chinse
+ var to:AiSupportLanguage = .english
+ var path = ""
+ var name = ""
+ var duration = 0
+ var createTime = ""
+ var origin = ""
+
+ var translate = ""
+ var summary = ""
+ var favorite = "0"
+
+
+}
v.textColor = .rgb(0x121212)
v.font = .regular(20)
v.textAlignment = .center
- v.text = "Deep Gen2 Max"
+ v.text = BleManager.shared.connectPeripheral?.device.name ?? ""
}
desLabel.do { (v) in
v.textColor = .rgb(0x121212)
--- /dev/null
+//
+// PopMenu.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/23.
+//
+
+import UIKit
+
+class PopMenu: BasePresentView2 {
+ let contentView = UIView()
+ fileprivate let fontItem = MenuItem()
+ fileprivate let sharedItem = MenuItem()
+ fileprivate let deleteItem = MenuItem()
+
+ var shareCallback:(()->Void)?
+ var fontCallback:(()->Void)?
+ var deleteCallback:(()->Void)?
+
+ init() {
+ super.init(backgroundEnabled: true)
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func setupSubView() {
+ super.setupSubView()
+ addSubview(contentView)
+ contentView.addSubviews([fontItem,sharedItem,deleteItem])
+
+ fontItem.do { v in
+ v.icon.image = UIImage(named: "record_detail_font")
+ v.label.text = "字号"
+ v.yc.addTap(target: self, action: #selector(fontAction))
+ }
+ sharedItem.do { v in
+ v.icon.image = UIImage(named: "record_detail_share")
+ v.label.text = "分享"
+ v.yc.addTap(target: self, action: #selector(sharedAction))
+ }
+ deleteItem.do { v in
+ v.icon.image = UIImage(named: "record_detail_delete")
+ v.label.text = "删除"
+ v.yc.addTap(target: self, action: #selector(deleteAction))
+ }
+ }
+ override func setupLayout() {
+ super.setupLayout()
+ contentView.do { (v) in
+ v.backgroundColor = .white
+ v.yc.setCornerRadius(20)
+ }
+ fontItem.snp.makeConstraints { make in
+ make.left.equalToSuperview()
+ make.top.equalToSuperview().inset(12)
+ make.width.equalToSuperview()
+ make.height.equalTo(34)
+ }
+ sharedItem.snp.makeConstraints { make in
+ make.left.equalToSuperview()
+ make.top.equalTo(fontItem.snp.bottom)
+ make.width.equalToSuperview()
+ make.height.equalTo(34)
+ }
+ deleteItem.snp.makeConstraints { make in
+ make.left.equalToSuperview()
+ make.top.equalTo(sharedItem.snp.bottom)
+ make.width.equalToSuperview()
+ make.height.equalTo(34)
+ }
+ }
+
+ override func setupStyle() {
+ super.setupStyle()
+ contentView.snp.makeConstraints { make in
+ make.right.equalToSuperview().inset(18)
+ make.height.equalTo(136)
+ make.width.equalTo(106)
+ make.bottom.equalToSuperview().inset(113)
+ }
+
+ }
+ @objc func fontAction(){
+ fontCallback?()
+ hide()
+ }
+ @objc func sharedAction(){
+ shareCallback?()
+ hide()
+ }
+ @objc func deleteAction(){
+ deleteCallback?()
+ hide()
+ }
+}
+
+fileprivate class MenuItem: BaseView {
+ let label = UILabel()
+ let icon = UIImageView()
+
+ override func setupViews() {
+ addSubviews([label,icon])
+ label.do { v in
+ v.font = .regular(14)
+ v.textColor = .hexString("#232323")
+
+ }
+ icon.do { v in
+ }
+ }
+ override func setupLayout() {
+ icon.snp.makeConstraints { make in
+ make.size.equalTo(34)
+ make.left.equalToSuperview().inset(8)
+ make.top.equalToSuperview()
+ }
+ label.snp.makeConstraints { make in
+ make.left.equalToSuperview().inset(46)
+ make.centerY.equalTo(icon)
+ }
+ }
+}
--- /dev/null
+//
+// PopPlayView.swift
+// ShenYin
+//
+// Created by liangshi on 2025/10/27.
+//
+
+import UIKit
+
+class PopPlayView: BasePresentView2 {
+ let contentView = UIView()
+ private let titleLabel = UILabel()
+
+ let slider = UISlider()
+ let progressLabel = UILabel()
+ let durationLabel = UILabel()
+ let playBtn = UIButton(type: .custom)
+ let closeBtn = UIButton(type: .custom)
+ var filePath:String?
+ let duration:Int
+
+ init(filePath path:String?,fieldId:String?,duration:Int) {
+ self.filePath = path
+ self.duration = duration
+ super.init(backgroundEnabled: false)
+ if let id = fieldId{
+ loadFile(filedId: id)
+ }
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ func loadFile(filedId id:String){
+ let api = CommomApi.recordUrl(filedId: id)
+ HttpClient.request(api) {[weak self] (model:CommonDataModel,res) in
+ guard let self = self else {return}
+ if model.isSuccess{
+ startDownload(url: model.data)
+ }
+ }
+ }
+ func startDownload(url:String){
+ // let url = "https://dc-cloud-priv.tos-cn-guangzhou.volces.com/music-file/2025_10_09/1976135290430767105.mp3"
+ HttpClient.download(url: url,type: "wav"){[weak self] result in
+ guard let self = self else {return}
+ if let path = result{
+ filePath = path
+ startPlay()
+ }
+ }
+ }
+
+ override func setupSubView() {
+ super.setupSubView()
+ addSubview(contentView)
+ addSubview(closeBtn)
+ contentView.addSubviews([titleLabel,slider,progressLabel,durationLabel,playBtn])
+
+ slider.do { v in
+ // v.backgroundColor = .red
+ v.minimumValue = 0
+ v.maximumValue = Float(duration)
+ v.value = 0
+ v.minimumTrackTintColor = .color(.theme)
+ v.setThumbImage(UIColor.color(.theme).imageCircle(with: CGSize(width: 20, height: 20)), for: .normal)
+ v.addTarget(self, action: #selector(sliderChanged(_:)), for: .valueChanged) // continuous changes
+
+ }
+ progressLabel.do { v in
+ v.text = "00:00"
+ v.textColor = .hexString("#666666")
+ v.textAlignment = .center
+ v.font = .regular(12)
+ }
+ durationLabel.do { v in
+ v.text = YLToos.formatSeconds1(duration)
+ v.textColor = progressLabel.textColor
+ v.textAlignment = .center
+ v.font = .regular(12)
+ }
+ playBtn.do { v in
+ v.setImage(UIImage(named: "record_play 3"), for: .normal)
+ v.setImage(UIImage(named: "record_pause 3"), for: .selected)
+ v.addTarget(self, action: #selector(btnAction), for: .touchUpInside)
+ v.isEnabled = false
+ }
+ closeBtn.do { v in
+ v.setImage(UIImage(named: "close_btn_1"), for: .normal)
+ v.setImage(UIImage(named: "close_btn_1"), for: .selected)
+ v.addTarget(self, action: #selector(closeAction), for: .touchUpInside)
+ }
+
+ AudioPlayerManager.shared.progressCallback = {[weak self] current,duration in
+ guard let self = self else {return}
+ slider.maximumValue = duration
+ slider.setValue(current, animated: true)
+ progressLabel.text = YLToos.formatSeconds1(Int(current))
+ durationLabel.text = YLToos.formatSeconds1(Int(duration))
+ }
+ startPlay()
+ }
+ override func setupLayout() {
+ super.setupLayout()
+ contentView.do { (v) in
+ v.backgroundColor = .white
+ v.yc.setCornerRadius(20)
+ }
+
+ titleLabel.snp.makeConstraints { (m) in
+ m.top.equalToSuperview().inset(24)
+ m.left.right.equalToSuperview()
+ }
+ slider.snp.makeConstraints { make in
+ // make.width.equalTo(200)
+ make.height.equalTo(40)
+ make.centerX.equalToSuperview()
+ make.left.right.equalToSuperview().inset(40)
+ make.top.equalToSuperview().offset(60)
+ }
+ progressLabel.snp.makeConstraints { make in
+ make.left.equalTo(slider)
+ make.top.equalTo(slider.snp.bottom)
+ }
+ durationLabel.snp.makeConstraints { make in
+ make.right.equalTo(slider)
+ make.top.equalTo(slider.snp.bottom)
+ }
+ playBtn.snp.makeConstraints { make in
+ make.size.equalTo(60)
+ make.centerX.equalToSuperview()
+ make.bottom.equalToSuperview().inset(20)
+ }
+ closeBtn.snp.makeConstraints { make in
+ make.size.equalTo(60)
+ make.right.equalToSuperview()
+ make.bottom.equalTo(contentView.snp.top).offset(10)
+ }
+ }
+
+ override func setupStyle() {
+ super.setupStyle()
+ contentView.snp.makeConstraints { make in
+ make.left.right.equalToSuperview().inset(18)
+ make.height.equalTo(200)
+ make.center.equalToSuperview()
+ }
+ titleLabel.do { (v) in
+ v.textColor = .rgb(0x121212)
+ v.font = .bold(20)
+ v.textAlignment = .center
+ v.text = "播放录音"
+ }
+
+ }
+ @objc func closeAction(){
+ AudioPlayerManager.shared.stop()
+ hide()
+ }
+
+ @objc func btnAction(){
+ playBtn.isSelected = !playBtn.isSelected
+ if playBtn.isSelected {
+ AudioPlayerManager.shared.start()
+ }
+ else{
+ AudioPlayerManager.shared.pause()
+ }
+ }
+ @objc func sliderChanged(_ slider:UISlider){
+ let value = YLToos.formatSeconds1(Int(slider.value))
+ Logger.debug(slider.value)
+ if let text = progressLabel.text, text != value {
+ progressLabel.text = value
+ }
+
+ AudioPlayerManager.shared.setDuration(slider.value)
+ }
+
+ func startPlay(){
+ playBtn.isEnabled = true
+ guard let path = filePath else {
+ return
+ }
+// guard let filePath = Bundle.main.path(forResource: "test", ofType: "mp3") else {return}
+ AudioPlayerManager.shared.play(filePath: path)
+ AudioPlayerManager.shared.start()
+ playBtn.isSelected = true
+ }
+}
+
let contentView = UIView()
private let titleLabel = UILabel()
private let textFiledBg = UIView()
- private let textFiled = UITextField()
- private let cancelButton = CustomButton()
+ let textFiled = UITextField()
+ let cancelButton = CustomButton()
private let okButton = CustomButton()
var cancelTap:(()->Void)?
- var okTap:(()->Void)?
+ var okTap:((_ text:String)->Void)?
init() {
super.init(backgroundEnabled: false)
}
textFiled.do { v in
- v.text = Date().format(.full2)
+// v.text = Date().format(.full3)
+ v.placeholder = "请输入录音名字"
v.font = .bold(16)
v.textColor = .hexString("#121212")
+ v.becomeFirstResponder()
}
cancelButton.do { (v) in
v.setTitle("删除", for: .normal)
}
}
@objc func okButtonAction(){
- okTap?()
+ guard let text = textFiled.text,text.count > 0 else {
+ return
+ }
+ okTap?(text)
hide()
}
@objc func cancelButtonAction(){
pod 'DGActivityIndicatorView'#扫描雷达
pod 'DeviceKit', '~> 5.4.0'
pod 'CryptoSwift'
+
+ pod 'ZipArchive'#压缩
# pod 'MultiSlider'
# pod 'DSWaveformImage'
+++ /dev/null
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 77;
- objects = {
-
-/* Begin PBXBuildFile section */
- 059668912D6EC43400B8D41D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0596687E2D6EC43400B8D41D /* Assets.xcassets */; };
- 059668922D6EC43400B8D41D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 059668872D6EC43400B8D41D /* Main.storyboard */; };
- 059668932D6EC43400B8D41D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 059668852D6EC43400B8D41D /* LaunchScreen.storyboard */; };
- 059668952D6EC43400B8D41D /* OtherViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059668892D6EC43400B8D41D /* OtherViewController.swift */; };
- 059668962D6EC43400B8D41D /* PcmSound.m in Sources */ = {isa = PBXBuildFile; fileRef = 0596688B2D6EC43400B8D41D /* PcmSound.m */; };
- 059668972D6EC43400B8D41D /* SIViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0596688F2D6EC43400B8D41D /* SIViewController.swift */; };
- 059668982D6EC43400B8D41D /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0596688E2D6EC43400B8D41D /* SceneDelegate.swift */; };
- 059668992D6EC43400B8D41D /* ChatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0596687F2D6EC43400B8D41D /* ChatViewController.swift */; };
- 0596689A2D6EC43400B8D41D /* PeripheralViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0596688C2D6EC43400B8D41D /* PeripheralViewController.swift */; };
- 0596689B2D6EC43400B8D41D /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059668882D6EC43400B8D41D /* MainViewController.swift */; };
- 0596689C2D6EC43400B8D41D /* RecordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0596688D2D6EC43400B8D41D /* RecordViewController.swift */; };
- 0596689D2D6EC43400B8D41D /* DialogueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059668802D6EC43400B8D41D /* DialogueViewController.swift */; };
- 0596689E2D6EC43400B8D41D /* Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059668812D6EC43400B8D41D /* Extension.swift */; };
- 0596689F2D6EC43400B8D41D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0596687D2D6EC43400B8D41D /* AppDelegate.swift */; };
- 059A002C2E6839A8002007C6 /* DeviceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059A002A2E6839A8002007C6 /* DeviceViewController.swift */; };
- 059A002D2E6839A8002007C6 /* CallViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059A00292E6839A8002007C6 /* CallViewController.swift */; };
- 059A002E2E6839A8002007C6 /* StereoCallViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 059A002B2E6839A8002007C6 /* StereoCallViewController.swift */; };
- 05A2920D2DAFCA8B00E1C39E /* ConfigViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05A2920C2DAFCA8B00E1C39E /* ConfigViewController.swift */; };
- 05AD42B02E432BED00BAC3E8 /* JoyGemAI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05A2A1A42D782B39000C198A /* JoyGemAI.framework */; };
- 05AD42B12E432BED00BAC3E8 /* JoyGemAI.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 05A2A1A42D782B39000C198A /* JoyGemAI.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
- 05DB1F842DCDFFBC000761BF /* RecordCallViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05DB1F832DCDFFBC000761BF /* RecordCallViewController.swift */; };
- 69CE07F7C0E911EA772186EB /* Pods_JoyGemAIDemo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2CFD5E22618961880D18F6A /* Pods_JoyGemAIDemo.framework */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXCopyFilesBuildPhase section */
- 05AD42B22E432BED00BAC3E8 /* Embed Frameworks */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "";
- dstSubfolderSpec = 10;
- files = (
- 05AD42B12E432BED00BAC3E8 /* JoyGemAI.framework in Embed Frameworks */,
- );
- name = "Embed Frameworks";
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
- 0596687D2D6EC43400B8D41D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
- 0596687E2D6EC43400B8D41D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
- 0596687F2D6EC43400B8D41D /* ChatViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatViewController.swift; sourceTree = "<group>"; };
- 059668802D6EC43400B8D41D /* DialogueViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DialogueViewController.swift; sourceTree = "<group>"; };
- 059668812D6EC43400B8D41D /* Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extension.swift; sourceTree = "<group>"; };
- 059668822D6EC43400B8D41D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- 059668832D6EC43400B8D41D /* JoyGemAIDemo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JoyGemAIDemo-Bridging-Header.h"; sourceTree = "<group>"; };
- 059668842D6EC43400B8D41D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
- 059668862D6EC43400B8D41D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
- 059668882D6EC43400B8D41D /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
- 059668892D6EC43400B8D41D /* OtherViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtherViewController.swift; sourceTree = "<group>"; };
- 0596688A2D6EC43400B8D41D /* PcmSound.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PcmSound.h; sourceTree = "<group>"; };
- 0596688B2D6EC43400B8D41D /* PcmSound.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PcmSound.m; sourceTree = "<group>"; };
- 0596688C2D6EC43400B8D41D /* PeripheralViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeripheralViewController.swift; sourceTree = "<group>"; };
- 0596688D2D6EC43400B8D41D /* RecordViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordViewController.swift; sourceTree = "<group>"; };
- 0596688E2D6EC43400B8D41D /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
- 0596688F2D6EC43400B8D41D /* SIViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SIViewController.swift; sourceTree = "<group>"; };
- 059A00292E6839A8002007C6 /* CallViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallViewController.swift; sourceTree = "<group>"; };
- 059A002A2E6839A8002007C6 /* DeviceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceViewController.swift; sourceTree = "<group>"; };
- 059A002B2E6839A8002007C6 /* StereoCallViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StereoCallViewController.swift; sourceTree = "<group>"; };
- 05A2920C2DAFCA8B00E1C39E /* ConfigViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigViewController.swift; sourceTree = "<group>"; };
- 05A2A1A42D782B39000C198A /* JoyGemAI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JoyGemAI.framework; sourceTree = "<group>"; };
- 05DB1F832DCDFFBC000761BF /* RecordCallViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordCallViewController.swift; sourceTree = "<group>"; };
- 05F2E4562D599F3E0031BB28 /* JoyGemAIDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JoyGemAIDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
- AF63D4AE63F8369636743944 /* Pods-JoygemAIDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JoygemAIDemo.release.xcconfig"; path = "Target Support Files/Pods-JoygemAIDemo/Pods-JoygemAIDemo.release.xcconfig"; sourceTree = "<group>"; };
- B2CFD5E22618961880D18F6A /* Pods_JoyGemAIDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JoyGemAIDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- BA3EBF65C77EB1A42DBDDA92 /* Pods-JoyGemAIDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JoyGemAIDemo.release.xcconfig"; path = "Target Support Files/Pods-JoyGemAIDemo/Pods-JoyGemAIDemo.release.xcconfig"; sourceTree = "<group>"; };
- DBDAAF1DCB03B45B52DECA3C /* Pods-JoyGemAIDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JoyGemAIDemo.debug.xcconfig"; path = "Target Support Files/Pods-JoyGemAIDemo/Pods-JoyGemAIDemo.debug.xcconfig"; sourceTree = "<group>"; };
- FD1732B60B5D0B4F6B8B0535 /* Pods-JoygemAIDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JoygemAIDemo.debug.xcconfig"; path = "Target Support Files/Pods-JoygemAIDemo/Pods-JoygemAIDemo.debug.xcconfig"; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 05F2E4532D599F3E0031BB28 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 69CE07F7C0E911EA772186EB /* Pods_JoyGemAIDemo.framework in Frameworks */,
- 05AD42B02E432BED00BAC3E8 /* JoyGemAI.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 059668902D6EC43400B8D41D /* JoyGemAIDemo */ = {
- isa = PBXGroup;
- children = (
- 0596687D2D6EC43400B8D41D /* AppDelegate.swift */,
- 059A00292E6839A8002007C6 /* CallViewController.swift */,
- 0596687F2D6EC43400B8D41D /* ChatViewController.swift */,
- 05A2920C2DAFCA8B00E1C39E /* ConfigViewController.swift */,
- 059A002A2E6839A8002007C6 /* DeviceViewController.swift */,
- 059668802D6EC43400B8D41D /* DialogueViewController.swift */,
- 059668812D6EC43400B8D41D /* Extension.swift */,
- 059668882D6EC43400B8D41D /* MainViewController.swift */,
- 059668892D6EC43400B8D41D /* OtherViewController.swift */,
- 0596688C2D6EC43400B8D41D /* PeripheralViewController.swift */,
- 05DB1F832DCDFFBC000761BF /* RecordCallViewController.swift */,
- 0596688D2D6EC43400B8D41D /* RecordViewController.swift */,
- 0596688E2D6EC43400B8D41D /* SceneDelegate.swift */,
- 0596688F2D6EC43400B8D41D /* SIViewController.swift */,
- 059A002B2E6839A8002007C6 /* StereoCallViewController.swift */,
- 0596687E2D6EC43400B8D41D /* Assets.xcassets */,
- 059668852D6EC43400B8D41D /* LaunchScreen.storyboard */,
- 059668872D6EC43400B8D41D /* Main.storyboard */,
- 059668832D6EC43400B8D41D /* JoyGemAIDemo-Bridging-Header.h */,
- 0596688A2D6EC43400B8D41D /* PcmSound.h */,
- 0596688B2D6EC43400B8D41D /* PcmSound.m */,
- 059668822D6EC43400B8D41D /* Info.plist */,
- );
- path = JoyGemAIDemo;
- sourceTree = "<group>";
- };
- 05F2E44D2D599F3E0031BB28 = {
- isa = PBXGroup;
- children = (
- 059668902D6EC43400B8D41D /* JoyGemAIDemo */,
- 05F2E4572D599F3E0031BB28 /* Products */,
- 63974ECFCD81206BA97C00D7 /* Pods */,
- 8752043BF3087F4F7594B5D7 /* Frameworks */,
- );
- sourceTree = "<group>";
- };
- 05F2E4572D599F3E0031BB28 /* Products */ = {
- isa = PBXGroup;
- children = (
- 05F2E4562D599F3E0031BB28 /* JoyGemAIDemo.app */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 63974ECFCD81206BA97C00D7 /* Pods */ = {
- isa = PBXGroup;
- children = (
- FD1732B60B5D0B4F6B8B0535 /* Pods-JoygemAIDemo.debug.xcconfig */,
- AF63D4AE63F8369636743944 /* Pods-JoygemAIDemo.release.xcconfig */,
- DBDAAF1DCB03B45B52DECA3C /* Pods-JoyGemAIDemo.debug.xcconfig */,
- BA3EBF65C77EB1A42DBDDA92 /* Pods-JoyGemAIDemo.release.xcconfig */,
- );
- path = Pods;
- sourceTree = "<group>";
- };
- 8752043BF3087F4F7594B5D7 /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 05A2A1A42D782B39000C198A /* JoyGemAI.framework */,
- B2CFD5E22618961880D18F6A /* Pods_JoyGemAIDemo.framework */,
- );
- name = Frameworks;
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 05F2E4552D599F3E0031BB28 /* JoyGemAIDemo */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 05F2E4692D599F400031BB28 /* Build configuration list for PBXNativeTarget "JoyGemAIDemo" */;
- buildPhases = (
- DA797B232201B60B79B0C84E /* [CP] Check Pods Manifest.lock */,
- 05F2E4522D599F3E0031BB28 /* Sources */,
- 05F2E4532D599F3E0031BB28 /* Frameworks */,
- 05F2E4542D599F3E0031BB28 /* Resources */,
- 70A64C05DE767D26E2D3F43D /* [CP] Embed Pods Frameworks */,
- 05AD42B22E432BED00BAC3E8 /* Embed Frameworks */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = JoyGemAIDemo;
- productName = JoygemAIDemo;
- productReference = 05F2E4562D599F3E0031BB28 /* JoyGemAIDemo.app */;
- productType = "com.apple.product-type.application";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 05F2E44E2D599F3E0031BB28 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- BuildIndependentTargetsInParallel = 1;
- LastSwiftUpdateCheck = 1600;
- LastUpgradeCheck = 1600;
- TargetAttributes = {
- 05F2E4552D599F3E0031BB28 = {
- CreatedOnToolsVersion = 16.0;
- LastSwiftMigration = 1600;
- };
- };
- };
- buildConfigurationList = 05F2E4512D599F3E0031BB28 /* Build configuration list for PBXProject "JoyGemAIDemo" */;
- developmentRegion = en;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- );
- mainGroup = 05F2E44D2D599F3E0031BB28;
- minimizedProjectReferenceProxies = 1;
- preferredProjectObjectVersion = 77;
- productRefGroup = 05F2E4572D599F3E0031BB28 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 05F2E4552D599F3E0031BB28 /* JoyGemAIDemo */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 05F2E4542D599F3E0031BB28 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 059668912D6EC43400B8D41D /* Assets.xcassets in Resources */,
- 059668922D6EC43400B8D41D /* Main.storyboard in Resources */,
- 059668932D6EC43400B8D41D /* LaunchScreen.storyboard in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
- 70A64C05DE767D26E2D3F43D /* [CP] Embed Pods Frameworks */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-JoyGemAIDemo/Pods-JoyGemAIDemo-frameworks-${CONFIGURATION}-input-files.xcfilelist",
- );
- inputPaths = (
- );
- name = "[CP] Embed Pods Frameworks";
- outputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-JoyGemAIDemo/Pods-JoyGemAIDemo-frameworks-${CONFIGURATION}-output-files.xcfilelist",
- );
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-JoyGemAIDemo/Pods-JoyGemAIDemo-frameworks.sh\"\n";
- showEnvVarsInLog = 0;
- };
- DA797B232201B60B79B0C84E /* [CP] Check Pods Manifest.lock */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- );
- inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
- );
- name = "[CP] Check Pods Manifest.lock";
- outputFileListPaths = (
- );
- outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-JoyGemAIDemo-checkManifestLockResult.txt",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
- showEnvVarsInLog = 0;
- };
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 05F2E4522D599F3E0031BB28 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 059668952D6EC43400B8D41D /* OtherViewController.swift in Sources */,
- 059668962D6EC43400B8D41D /* PcmSound.m in Sources */,
- 05A2920D2DAFCA8B00E1C39E /* ConfigViewController.swift in Sources */,
- 059668972D6EC43400B8D41D /* SIViewController.swift in Sources */,
- 059668982D6EC43400B8D41D /* SceneDelegate.swift in Sources */,
- 05DB1F842DCDFFBC000761BF /* RecordCallViewController.swift in Sources */,
- 059668992D6EC43400B8D41D /* ChatViewController.swift in Sources */,
- 0596689A2D6EC43400B8D41D /* PeripheralViewController.swift in Sources */,
- 0596689B2D6EC43400B8D41D /* MainViewController.swift in Sources */,
- 0596689C2D6EC43400B8D41D /* RecordViewController.swift in Sources */,
- 0596689D2D6EC43400B8D41D /* DialogueViewController.swift in Sources */,
- 0596689E2D6EC43400B8D41D /* Extension.swift in Sources */,
- 059A002C2E6839A8002007C6 /* DeviceViewController.swift in Sources */,
- 059A002D2E6839A8002007C6 /* CallViewController.swift in Sources */,
- 059A002E2E6839A8002007C6 /* StereoCallViewController.swift in Sources */,
- 0596689F2D6EC43400B8D41D /* AppDelegate.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXVariantGroup section */
- 059668852D6EC43400B8D41D /* LaunchScreen.storyboard */ = {
- isa = PBXVariantGroup;
- children = (
- 059668842D6EC43400B8D41D /* Base */,
- );
- name = LaunchScreen.storyboard;
- sourceTree = "<group>";
- };
- 059668872D6EC43400B8D41D /* Main.storyboard */ = {
- isa = PBXVariantGroup;
- children = (
- 059668862D6EC43400B8D41D /* Base */,
- );
- name = Main.storyboard;
- sourceTree = "<group>";
- };
-/* End PBXVariantGroup section */
-
-/* Begin XCBuildConfiguration section */
- 05F2E46A2D599F400031BB28 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = DBDAAF1DCB03B45B52DECA3C /* Pods-JoyGemAIDemo.debug.xcconfig */;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CLANG_ENABLE_MODULES = YES;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = M33X987285;
- ENABLE_USER_SCRIPT_SANDBOXING = NO;
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)",
- );
- GENERATE_INFOPLIST_FILE = YES;
- HEADER_SEARCH_PATHS = (
- "$(inherited)",
- "\"${PODS_CONFIGURATION_BUILD_DIR}/SVProgressHUD/SVProgressHUD.framework/Headers\"",
- "\"${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers\"",
- "\"${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket/SocketRocket.framework/Headers\"",
- "\"$(SRCROOT)/JoyGemAI.framework/Headers\"",
- );
- INFOPLIST_FILE = JoyGemAIDemo/Info.plist;
- INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "蓝牙";
- INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "蓝牙";
- INFOPLIST_KEY_NSMicrophoneUsageDescription = "麦克风";
- INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
- INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
- INFOPLIST_KEY_UIMainStoryboardFile = Main;
- INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
- MARKETING_VERSION = 1.0.1;
- OTHER_LDFLAGS = (
- "-ObjC",
- "-all_load",
- "$(inherited)",
- "-l\"icucore\"",
- "-l\"swiftCoreGraphics\"",
- "-framework",
- "\"CFNetwork\"",
- "-framework",
- "\"QuartzCore\"",
- "-framework",
- "\"SVProgressHUD\"",
- "-framework",
- "\"Security\"",
- "-framework",
- "\"SnapKit\"",
- "-framework",
- "\"SocketRocket\"",
- );
- PRODUCT_BUNDLE_IDENTIFIER = com.joygem.aidemo;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
- SUPPORTS_MACCATALYST = NO;
- SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
- SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_OBJC_BRIDGING_HEADER = "JoyGemAIDemo/JoyGemAIDemo-Bridging-Header.h";
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = 1;
- };
- name = Debug;
- };
- 05F2E46B2D599F400031BB28 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = BA3EBF65C77EB1A42DBDDA92 /* Pods-JoyGemAIDemo.release.xcconfig */;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CLANG_ENABLE_MODULES = YES;
- CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_TEAM = M33X987285;
- ENABLE_USER_SCRIPT_SANDBOXING = NO;
- FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)",
- );
- GENERATE_INFOPLIST_FILE = YES;
- HEADER_SEARCH_PATHS = (
- "$(inherited)",
- "\"${PODS_CONFIGURATION_BUILD_DIR}/SVProgressHUD/SVProgressHUD.framework/Headers\"",
- "\"${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers\"",
- "\"${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket/SocketRocket.framework/Headers\"",
- "\"$(SRCROOT)/JoyGemAI.framework/Headers\"",
- );
- INFOPLIST_FILE = JoyGemAIDemo/Info.plist;
- INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "蓝牙";
- INFOPLIST_KEY_NSBluetoothPeripheralUsageDescription = "蓝牙";
- INFOPLIST_KEY_NSMicrophoneUsageDescription = "麦克风";
- INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
- INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
- INFOPLIST_KEY_UIMainStoryboardFile = Main;
- INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
- INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait";
- IPHONEOS_DEPLOYMENT_TARGET = 15.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- );
- MARKETING_VERSION = 1.0.1;
- OTHER_LDFLAGS = (
- "-ObjC",
- "-all_load",
- "$(inherited)",
- "-l\"icucore\"",
- "-l\"swiftCoreGraphics\"",
- "-framework",
- "\"CFNetwork\"",
- "-framework",
- "\"QuartzCore\"",
- "-framework",
- "\"SVProgressHUD\"",
- "-framework",
- "\"Security\"",
- "-framework",
- "\"SnapKit\"",
- "-framework",
- "\"SocketRocket\"",
- );
- PRODUCT_BUNDLE_IDENTIFIER = com.joygem.aidemo;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
- SUPPORTS_MACCATALYST = NO;
- SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
- SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_OBJC_BRIDGING_HEADER = "JoyGemAIDemo/JoyGemAIDemo-Bridging-Header.h";
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = 1;
- };
- name = Release;
- };
- 05F2E46C2D599F400031BB28 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = dwarf;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 18.0;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- MTL_FAST_MATH = YES;
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = iphoneos;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- };
- name = Debug;
- };
- 05F2E46D2D599F400031BB28 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 18.0;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = NO;
- MTL_FAST_MATH = YES;
- SDKROOT = iphoneos;
- SWIFT_COMPILATION_MODE = wholemodule;
- VALIDATE_PRODUCT = YES;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 05F2E4512D599F3E0031BB28 /* Build configuration list for PBXProject "JoyGemAIDemo" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 05F2E46C2D599F400031BB28 /* Debug */,
- 05F2E46D2D599F400031BB28 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 05F2E4692D599F400031BB28 /* Build configuration list for PBXNativeTarget "JoyGemAIDemo" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 05F2E46A2D599F400031BB28 /* Debug */,
- 05F2E46B2D599F400031BB28 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 05F2E44E2D599F3E0031BB28 /* Project object */;
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
- version = "1.0">
- <FileRef
- location = "self:">
- </FileRef>
-</Workspace>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<Scheme
- LastUpgradeVersion = "1600"
- version = "1.7">
- <BuildAction
- parallelizeBuildables = "YES"
- buildImplicitDependencies = "YES"
- buildArchitectures = "Automatic">
- <BuildActionEntries>
- <BuildActionEntry
- buildForTesting = "YES"
- buildForRunning = "YES"
- buildForProfiling = "YES"
- buildForArchiving = "YES"
- buildForAnalyzing = "YES">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "05F2E4552D599F3E0031BB28"
- BuildableName = "JoyGemAIDemo.app"
- BlueprintName = "JoyGemAIDemo"
- ReferencedContainer = "container:JoyGemAIDemo.xcodeproj">
- </BuildableReference>
- </BuildActionEntry>
- </BuildActionEntries>
- </BuildAction>
- <TestAction
- buildConfiguration = "Debug"
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- shouldUseLaunchSchemeArgsEnv = "YES"
- shouldAutocreateTestPlan = "YES">
- </TestAction>
- <LaunchAction
- buildConfiguration = "Debug"
- selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
- selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
- launchStyle = "0"
- useCustomWorkingDirectory = "NO"
- ignoresPersistentStateOnLaunch = "NO"
- debugDocumentVersioning = "YES"
- debugServiceExtension = "internal"
- allowLocationSimulation = "YES">
- <BuildableProductRunnable
- runnableDebuggingMode = "0">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "05F2E4552D599F3E0031BB28"
- BuildableName = "JoyGemAIDemo.app"
- BlueprintName = "JoyGemAIDemo"
- ReferencedContainer = "container:JoyGemAIDemo.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- </LaunchAction>
- <ProfileAction
- buildConfiguration = "Release"
- shouldUseLaunchSchemeArgsEnv = "YES"
- savedToolIdentifier = ""
- useCustomWorkingDirectory = "NO"
- debugDocumentVersioning = "YES">
- <BuildableProductRunnable
- runnableDebuggingMode = "0">
- <BuildableReference
- BuildableIdentifier = "primary"
- BlueprintIdentifier = "05F2E4552D599F3E0031BB28"
- BuildableName = "JoyGemAIDemo.app"
- BlueprintName = "JoyGemAIDemo"
- ReferencedContainer = "container:JoyGemAIDemo.xcodeproj">
- </BuildableReference>
- </BuildableProductRunnable>
- </ProfileAction>
- <AnalyzeAction
- buildConfiguration = "Debug">
- </AnalyzeAction>
- <ArchiveAction
- buildConfiguration = "Release"
- revealArchiveInOrganizer = "YES">
- </ArchiveAction>
-</Scheme>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<Workspace
- version = "1.0">
- <FileRef
- location = "group:JoyGemAIDemo.xcodeproj">
- </FileRef>
- <FileRef
- location = "group:Pods/Pods.xcodeproj">
- </FileRef>
-</Workspace>
+++ /dev/null
-//
-// AppDelegate.swift
-// JoyGemAIDemo
-//
-// Created by JoyGem on 2025/2/10.
-//
-
-import UIKit
-import AVFoundation
-
-@main
-class AppDelegate: UIResponder, UIApplicationDelegate {
-
-
- func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
- // Override point for customization after application launch.
- // 添加观察者
-// NotificationCenter.default.addObserver(
-// self,
-// selector: #selector(handleRouteChange),
-// name: AVAudioSession.routeChangeNotification,
-// object: nil
-// )
-//
-// let dir = NSTemporaryDirectory()
-// debugPrint(dir)
-
- return true
- }
-
- // MARK: UISceneSession Lifecycle
-
- func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
- // Called when a new scene session is being created.
- // Use this method to select a configuration to create the new scene with.
- return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
- }
-
- func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
- // Called when the user discards a scene session.
- // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
- // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
- }
-
- @objc func handleRouteChange(notification: Notification) {
- guard let userInfo = notification.userInfo,
- let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt,
- let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else {
- return
- }
-
- switch reason {
- case .unknown:
- print("Audio category unknown")
- case .newDeviceAvailable:
- // 新设备可用(如耳机插入)
- print("Audio category New device available")
- case .oldDeviceUnavailable:
- // 旧设备不可用(如耳机拔出)
- print("Audio category Old device unavailable")
- case .categoryChange:
- // 音频类别发生变化
- print("Audio category changed")
- case .noSuitableRouteForCategory:
- print("Audio category noSuitableRouteForCategory")
- case .override:
- print("Audio category override")
- case .wakeFromSleep:
- print("Audio category wakeFromSleep")
- case .routeConfigurationChange:
- print("Audio category routeConfigurationChange")
- @unknown default:
- print("Audio category default")
- }
- }
-
-}
-
+++ /dev/null
-{
- "colors" : [
- {
- "idiom" : "universal"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
+++ /dev/null
-{
- "images" : [
- {
- "filename" : "20250226-104946.jpeg",
- "idiom" : "universal",
- "platform" : "ios",
- "size" : "1024x1024"
- },
- {
- "appearances" : [
- {
- "appearance" : "luminosity",
- "value" : "dark"
- }
- ],
- "idiom" : "universal",
- "platform" : "ios",
- "size" : "1024x1024"
- },
- {
- "appearances" : [
- {
- "appearance" : "luminosity",
- "value" : "tinted"
- }
- ],
- "idiom" : "universal",
- "platform" : "ios",
- "size" : "1024x1024"
- }
- ],
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
+++ /dev/null
-{
- "info" : {
- "author" : "xcode",
- "version" : 1
- }
-}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
- <dependencies>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
- <capability name="Safe area layout guides" minToolsVersion="9.0"/>
- <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
- </dependencies>
- <scenes>
- <!--View Controller-->
- <scene sceneID="EHf-IW-A2E">
- <objects>
- <viewController id="01J-lp-oVM" sceneMemberID="viewController">
- <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
- <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
- <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
- </view>
- </viewController>
- <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
- </objects>
- <point key="canvasLocation" x="53" y="375"/>
- </scene>
- </scenes>
-</document>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23094" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="xWg-az-U1T">
- <device id="retina6_12" orientation="portrait" appearance="light"/>
- <dependencies>
- <deployment identifier="iOS"/>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23084"/>
- <capability name="Safe area layout guides" minToolsVersion="9.0"/>
- <capability name="System colors in document resources" minToolsVersion="11.0"/>
- <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
- </dependencies>
- <scenes>
- <!--Navigation Controller-->
- <scene sceneID="S4u-9K-FhC">
- <objects>
- <navigationController id="xWg-az-U1T" sceneMemberID="viewController">
- <navigationBar key="navigationBar" contentMode="scaleToFill" id="ygV-aH-lnK">
- <rect key="frame" x="0.0" y="59" width="393" height="44"/>
- <autoresizingMask key="autoresizingMask"/>
- </navigationBar>
- <connections>
- <segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="Dl6-7B-XNs"/>
- </connections>
- </navigationController>
- <placeholder placeholderIdentifier="IBFirstResponder" id="SGv-te-JbP" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
- </objects>
- <point key="canvasLocation" x="-1459" y="-101"/>
- </scene>
- <!--Main View Controller-->
- <scene sceneID="tne-QT-ifu">
- <objects>
- <viewController id="BYZ-38-t0r" customClass="MainViewController" customModule="JoygemAIDemo" customModuleProvider="target" sceneMemberID="viewController">
- <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
- <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
- <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
- <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
- <color key="backgroundColor" systemColor="systemBackgroundColor"/>
- </view>
- <navigationItem key="navigationItem" id="rRi-sQ-2mm"/>
- </viewController>
- <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
- </objects>
- <point key="canvasLocation" x="-474.04580152671753" y="-101.40845070422536"/>
- </scene>
- </scenes>
- <resources>
- <systemColor name="systemBackgroundColor">
- <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
- </systemColor>
- </resources>
-</document>
+++ /dev/null
-//
-// RecordCallViewController.swift
-// JoyGemAIPod
-//
-// Created by jjjs on 2025/5/6.
-//
-
-import UIKit
-import SnapKit
-import JoyGemAI
-import AVFoundation
-import SVProgressHUD
-
-class CallViewController: UIViewController {
-
- var textView : UITextView!
-
- var startButton : UIButton!
-
- var stopButton : UIButton!
-
- var messageList : [(String,UInt)] = []
-
- var recordFilePath : String?
-
- override func viewDidLoad() {
- super.viewDidLoad()
- view.backgroundColor = UIColor.white
- title = "通话录音"
-
- self.navigationController?.navigationBar.tintColor = UIColor.black
- self.navigationItem.rightBarButtonItems = [
- UIBarButtonItem(title: "播放录音", style: .done, target: self, action: #selector(playRecord))
- ]
-
- textView = UITextView()
- view.addSubview(textView)
- textView.snp.makeConstraints { make in
- make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
- make.leading.trailing.equalToSuperview()
- make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-100)
- }
- textView.backgroundColor = UIColor.gray
- startButton = UIButton(type: .custom)
- view.addSubview(startButton)
- startButton.snp.makeConstraints { make in
- make.top.equalTo(textView.snp.bottom).offset(20)
- make.centerX.equalToSuperview().multipliedBy(0.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- startButton.setTitle("开始", for: .normal)
- startButton.setTitleColor(UIColor.darkText, for: .normal)
- startButton.addTarget(self, action: #selector(startRecord), for: .touchUpInside)
-
- stopButton = UIButton(type: .custom)
- view.addSubview(stopButton)
- stopButton.snp.makeConstraints { make in
- make.top.equalTo(textView.snp.bottom).offset(20)
- make.centerX.equalToSuperview().multipliedBy(1.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- stopButton.setTitle("结束", for: .normal)
- stopButton.setTitleColor(UIColor.darkText, for: .normal)
- stopButton.addTarget(self, action: #selector(endRecord), for: .touchUpInside)
-
- // Do any additional setup after loading the view.
- JoyGemCallManager.shared().delegate = self
- }
-
- @objc func startRecord() {
- messageList.removeAll()
- textView.text = nil
- JoyGemCallManager.shared().start()
- }
-
- @objc func endRecord() {
- JoyGemCallManager.shared().stop()
- }
-
- var audioPlayer: AVAudioPlayer?
-
- ///播放最后一次录音文件
- @objc func playRecord() {
- guard let file = recordFilePath else {return;}
-
- do {
- // 创建 AVAudioPlayer 实例
- audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: file))
- audioPlayer?.prepareToPlay() // 准备播放
- audioPlayer?.play() // 播放音频
- } catch {
- debugPrint("播放音频时发生错误: \(error.localizedDescription)")
- }
- }
-
-}
-
-extension CallViewController : JoyGemCallManagerDelegate {
-
- func callManagerStopped(_ manager: JoyGemCallManager, reason code: JoyGemRecordStopCode) {
- if (code == .actively) {
- SVProgressHUD.showInfo(withStatus: "用户主动结束")
- } else {
- SVProgressHUD.showInfo(withStatus: "自动结束")
- ///判断当前蓝牙是否连接从而确定是否因为蓝牙断开造成的录音断开
- }
- }
-
- func callManagerNotonCall(_ manager: JoyGemCallManager) {
- SVProgressHUD.showInfo(withStatus: "未处于通话状态")
- }
-
- func callManager(_ manager: JoyGemCallManager, saveFile path: String) {
- debugPrint("path: \(path)")
- recordFilePath = path
- }
-
- func callManager(_ manager: JoyGemCallManager, stateChange code: JoyGemStateCode) {
- debugPrint("code: \(code)")
- }
-
- func callManager(_ manager: JoyGemCallManager, onError code: JoyGemErrorCode) {
-
- }
-
- func callManager(_ manager: JoyGemCallManager, didUpdateAsr model: JoyGemAsrModel) {
- debugPrint("text: \(model.text),index: \(model.index)")
- let msg = messageList.firstIndex (where: { (str,idx) in
- return idx == model.index;
- })
- if (msg == nil) {
- messageList.append((model.text,model.index))
- } else {
- messageList[msg!] = (model.text,model.index)
- }
-
- textView.text = messageList.compactMap({ (str,idx) in
- return str
- }).joined(separator: "\n")
- }
-
-}
-
-
+++ /dev/null
-//
-// ChatViewController.swift
-// JoyGemAIDemo
-//
-// Created by JoyGem on 2025/2/21.
-//
-
-import UIKit
-import JoyGemAI
-import AVFoundation
-import SVProgressHUD
-
-class ChatViewController: UIViewController {
-
- var isTtsPlaying = false
- internal var requestTextView : UITextView!
- internal var responseTextView : UITextView!
- internal var stateLabel : UILabel = UILabel()
-
- internal var singleButton : UIButton = UIButton(type: .custom)
-
- internal var chatButton : UIButton = UIButton(type: .custom)
-
- var speakers : [JoyGemSpeaker] = []
- var selectedSpeaker: JoyGemSpeaker?
-
- override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
- super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
-
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- deinit {
- if (!JoyGemChatManager.shared().supportEvent) {
- JoyGemChatManager.shared().removeObserver(self, forKeyPath: "isActive")
- }
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
- view.backgroundColor = UIColor.white
- title = "AI对话"
-
- self.navigationItem.rightBarButtonItems = [
- UIBarButtonItem(title: "角色", style: .done, target: self, action: #selector(speakerAction)),
- ]
-
- requestTextView = UITextView()
- view.addSubview(requestTextView)
- requestTextView.backgroundColor = UIColor.gray
- requestTextView.snp.makeConstraints { make in
- make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
- make.leading.trailing.equalToSuperview()
- make.bottom.equalTo(view.snp.centerY).offset(-50)
- }
- responseTextView = UITextView()
- view.addSubview(responseTextView)
- responseTextView.backgroundColor = UIColor.yellow
- responseTextView.snp.makeConstraints { make in
- make.leading.trailing.equalToSuperview()
- make.top.equalTo(requestTextView.snp.bottom)
- make.height.equalTo(requestTextView.snp.height)
- }
-
- view.addSubview(singleButton)
- singleButton.snp.makeConstraints { make in
- make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-60)
- make.height.equalTo(40)
- make.left.equalToSuperview().offset(20)
- make.right.equalTo(view.snp.centerX).offset(-20)
- }
- singleButton.setTitle("长按对话", for: .normal)
- singleButton.setTitle("松开结束", for: .highlighted)
- singleButton.setTitleColor(UIColor.black, for: .normal)
- singleButton.backgroundColor = UIColor.gray
- singleButton.addTarget(self, action: #selector(singleChatStart), for: .touchDown)
- singleButton.addTarget(self, action: #selector(singleChatEnd), for: .touchUpInside)
-
- view.addSubview(chatButton)
- chatButton.snp.makeConstraints { make in
- make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-60)
- make.height.equalTo(40)
- make.right.equalToSuperview().offset(-20)
- make.left.equalTo(view.snp.centerX).offset(20)
- }
- chatButton.setTitle("开启对话", for: .normal)
- chatButton.setTitle("结束对话", for: .selected)
- chatButton.backgroundColor = UIColor.gray
- chatButton.setTitleColor(UIColor.black, for: .normal)
- chatButton.addTarget(self, action: #selector(chatControl(sender:)), for: .touchUpInside)
-
- view.addSubview(stateLabel)
- stateLabel.snp.makeConstraints { make in
- make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-10)
- make.height.equalTo(40)
- make.width.equalTo(200)
- make.centerX.equalToSuperview()
- }
- stateLabel.textColor = UIColor.black
- stateLabel.text = "操作耳机"
-
- JoyGemChatManager.shared().delegate = self
- PcmSound.sharedInstance().delegate = self
-
- if (!JoyGemChatManager.shared().supportEvent) {
- JoyGemChatManager.shared().addObserver(self, forKeyPath: "isActive",options: [.new, .old], context: nil);
- }
- }
-
- override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
- if (keyPath == "isActive") {
- var isOpen = change?[NSKeyValueChangeKey.newKey] as? Bool
- if (isOpen == true) {
- SVProgressHUD.showInfo(withStatus: "AI对话开启")
- } else {
- SVProgressHUD.showInfo(withStatus: "AI对话结束")
- PcmSound.sharedInstance().cleanup()
- }
- }
- }
-
-
- override func viewWillDisappear(_ animated: Bool) {
- super.viewWillDisappear(animated)
-
- ///结束对话,但并不会终止正在播放的录音
- JoyGemChatManager.shared().stopChat()
- }
-
- @objc func singleChatStart() {
- JoyGemChatManager.shared().startSingleChat()
- }
-
- @objc func singleChatEnd() {
- JoyGemChatManager.shared().stopSingleChat()
- }
-
- @objc func chatControl(sender : UIButton) {
- if (sender.isSelected) {
- JoyGemChatManager.shared().stopChat()
- sender.isSelected = false
- } else {
- JoyGemChatManager.shared().startChat()
- sender.isSelected = true
- }
- }
-
- @objc func speakerAction() {
- ///获取用户信息
- JoyGemChatManager.shared().getSpeakerList {[weak self] speakers in
- self?.speakers = speakers;
- self?.showPickerView()
- }
- }
-
- func showPickerView() {
- // 创建 UIAlertController
- let alertController = UIAlertController(title: "选择一个选项", message: nil, preferredStyle: .actionSheet)
-
- for speaker in speakers {
- // 添加确认按钮
- let confirmAction = UIAlertAction(title: speaker.name, style: .default) { _ in
- // 处理确认选择
- JoyGemChatManager.shared().setSpeaker(speaker)
- }
- alertController.addAction(confirmAction)
- }
-
- // 添加取消按钮
- let cancelAction = UIAlertAction(title: "取消", style: .cancel, handler: nil)
- alertController.addAction(cancelAction)
-
- // 显示提示框
- present(alertController, animated: true, completion: nil)
- }
-}
-
-extension ChatViewController : UIPickerViewDelegate,UIPickerViewDataSource {
-
- func numberOfComponents(in pickerView: UIPickerView) -> Int {
- 1
- }
-
- func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
- return speakers.count
- }
-
- func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
- return speakers[row].name
- }
-
- func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
- selectedSpeaker = speakers[row]
- }
-}
-
-extension ChatViewController : JoyGemChatManagerDelegate {
-
-
- func chatManager(_ manager: JoyGemChatManager, stateChange code: JoyGemStateCode) {
- switch code {
- case .startRecord:
- if (isTtsPlaying) {
- isTtsPlaying = false
- PcmSound.sharedInstance().cleanup()
- PcmSound.sharedInstance().setup(16000, withchannels: 1)
- let options: AVAudioSession.CategoryOptions = [.allowBluetooth]
- do {
- try AVAudioSession.sharedInstance().setCategory(.playback, options: [options])
- try AVAudioSession.sharedInstance().setActive(true)
- } catch {
- print(error)
- }
- }
- stateLabel.text = "正在录音"
- break
- case .stopRecord:
- stateLabel.text = "操作耳机"
- break
- default:
- break
- }
- }
-
- func chatManager(_ manager: JoyGemChatManager, onError code: JoyGemErrorCode) {
-
- }
-
- func chatManager(_ manager: JoyGemChatManager, audioData data: Data?, finish isFinish: Bool) {
- if (!isTtsPlaying) {
- isTtsPlaying = true
- JoyGemChatManager.shared().playAudioStart()
- }
- PcmSound.sharedInstance().feed(data)
- }
-
- func chatManager(_ manager: JoyGemChatManager, requestText text: String?, index: UInt) {
-
- requestTextView.text = text;
-
- }
-
- func chatManager(_ manager: JoyGemChatManager, responseText text: String?, index: UInt, finish isFinish: Bool) {
- if (isFinish) {
- responseTextView.text = text;
- }
- }
-
- func chatManager(_ manager: JoyGemChatManager, eventUpdate event: JoyGemChatEvent) {
- switch event {
- case .begin:
- SVProgressHUD.showInfo(withStatus: "对话开始")
- case .end:
- SVProgressHUD.showInfo(withStatus: "对话结束")
- default:
- break
- }
- }
-}
-
-extension ChatViewController : PcmSoundDelegate {
-
- func remaining(_ frames: UInt) {
- print("[frame:\(frames)]");
- if (frames == 0) {
- JoyGemChatManager.shared().playAudioEnd()
- }
- }
-}
+++ /dev/null
-//
-// ConfigViewController.swift
-// JoyGemAIPod
-//
-// Created by jjjs on 2025/4/12.
-//
-
-import Foundation
-import JoyGemAI
-import SVProgressHUD
-
-class ConfigViewController: UIViewController {
-
- internal var batteryButton : UIButton = UIButton(type: .custom)
-
- internal var addressButton : UIButton = UIButton(type: .custom)
-
- internal var statusButton : UIButton = UIButton(type: .custom)
-
- internal var versionButton : UIButton = UIButton(type: .custom)
-
- internal var clearButton : UIButton = UIButton(type: .custom)
-
- internal var vadButton : UIButton = UIButton(type: .custom)
-
- deinit {
-
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
- view.backgroundColor = .white
- title = "配置"
-
- view.addSubview(batteryButton)
- batteryButton.snp.makeConstraints { make in
- make.top.equalTo(view.safeAreaLayoutGuide.snp.top).offset(60)
- make.height.equalTo(40)
- make.centerX.equalToSuperview()
- make.width.equalTo(200)
- }
- batteryButton.setTitle("获取电量", for: .normal)
- batteryButton.setTitleColor(UIColor.black, for: .normal)
- batteryButton.backgroundColor = UIColor.gray
- batteryButton.addTarget(self, action: #selector(batteryAction), for: .touchUpInside)
-
- view.addSubview(addressButton)
- addressButton.snp.makeConstraints { make in
- make.top.equalTo(batteryButton.snp.bottom).offset(60)
- make.height.equalTo(40)
- make.centerX.equalToSuperview()
- make.width.equalTo(200)
- }
- addressButton.setTitle("获取地址", for: .normal)
- addressButton.backgroundColor = UIColor.gray
- addressButton.setTitleColor(UIColor.black, for: .normal)
- addressButton.addTarget(self, action: #selector(addressAction), for: .touchUpInside)
-
- view.addSubview(statusButton)
- statusButton.snp.makeConstraints { make in
- make.top.equalTo(addressButton.snp.bottom).offset(60)
- make.height.equalTo(40)
- make.centerX.equalToSuperview()
- make.width.equalTo(200)
- }
- statusButton.setTitle("获取经典蓝牙连接状态", for: .normal)
- statusButton.backgroundColor = UIColor.gray
- statusButton.setTitleColor(UIColor.black, for: .normal)
- statusButton.addTarget(self, action: #selector(statusAction), for: .touchUpInside)
-
- view.addSubview(versionButton)
- versionButton.snp.makeConstraints { make in
- make.top.equalTo(statusButton.snp.bottom).offset(60)
- make.height.equalTo(40)
- make.centerX.equalToSuperview()
- make.width.equalTo(200)
- }
- versionButton.setTitle("获取软件版本号", for: .normal)
- versionButton.backgroundColor = UIColor.gray
- versionButton.setTitleColor(UIColor.black, for: .normal)
- versionButton.addTarget(self, action: #selector(versionAction), for: .touchUpInside)
-
- view.addSubview(clearButton)
- clearButton.snp.makeConstraints { make in
- make.top.equalTo(versionButton.snp.bottom).offset(60)
- make.height.equalTo(40)
- make.centerX.equalToSuperview()
- make.width.equalTo(200)
- }
- clearButton.setTitle("清理缓存文件夹", for: .normal)
- clearButton.backgroundColor = UIColor.gray
- clearButton.setTitleColor(UIColor.black, for: .normal)
- clearButton.addTarget(self, action: #selector(clearAction), for: .touchUpInside)
-
- view.addSubview(vadButton)
- vadButton.snp.makeConstraints { make in
- make.top.equalTo(clearButton.snp.bottom).offset(60)
- make.height.equalTo(40)
- make.centerX.equalToSuperview()
- make.width.equalTo(200)
- }
- vadButton.setTitle("设置VAD打断", for: .normal)
- vadButton.backgroundColor = UIColor.gray
- vadButton.setTitleColor(UIColor.black, for: .normal)
- vadButton.addTarget(self, action: #selector(vadSetAcition), for: .touchUpInside)
-
- JoyGemAIManager.shared().device.setBatteryListener { left, right in
- debugPrint("left:\(left)");
- debugPrint("right:\(right)");
- }
-
- JoyGemAIManager.shared().device.setStatusListener { bt, tws in
- debugPrint("btConnected:\(bt)");
- debugPrint("twsConnected:\(tws)");
- }
-
-
-
-
-
- }
-
- @objc func addressAction() {
- JoyGemAIManager.shared().device.macAddress { edr, ble in
- debugPrint("edr:\(edr)");
- debugPrint("ble:\(ble)");
- } error: { error in
- debugPrint("\(error!.localizedDescription)");
- }
-
- }
-
- @objc func batteryAction() {
- JoyGemAIManager.shared().device.updateBattery()
- }
-
- @objc func statusAction() {
- JoyGemAIManager.shared().device.updateStatus()
- }
-
- @objc func versionAction() {
- JoyGemAIManager.shared().device.software { version in
- debugPrint("version:\(version)");
- } error: { error in
- debugPrint("\(error!.localizedDescription)");
- }
- }
-
- @objc func clearAction() {
- JoyGemAIManager.shared().clearCacheDirectory()
- }
-
- @objc func vadSetAcition() {
- JoyGemAIManager.shared().device.setVADInterruptedStatus(true) { error in
- if (error == nil) {
- debugPrint("设置成功");
- } else {
- SVProgressHUD.showError(withStatus: error?.localizedDescription)
- }
- }
- }
-
- @objc func vadGetAcition() {
-
- }
-}
-
+++ /dev/null
-//
-// DeviceViewController.swift
-// JoyGemAIPod
-//
-// Created by jjjs on 2025/9/2.
-//
-
-import UIKit
-import JoyGemAI
-
-class DeviceViewController: UIViewController {
-
- let list:[(name:String,action:String)] = [
- ("获取EQ","eqGetAction"),
- ("设置EQ","eqSetAction"),
- ("获取自定义EQ","customEqGetAction"),
- ("设置自定义EQ","customEqSetAction"),
- ("重置自定义EQ","customEqResetAction"),
- ("查找耳机","findHeadphoneAction"),
- ]
-
- var tableView: UITableView!
-
- override func viewDidLoad() {
- super.viewDidLoad()
- title = "设备操作"
-
- self.navigationController?.navigationBar.tintColor = UIColor.black
-
- tableView = UITableView(frame: CGRectZero, style: UITableView.Style.grouped)
- tableView.register(UITableViewCell.classForCoder(), forCellReuseIdentifier: "cell")
- view.addSubview(tableView)
- tableView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
- tableView.dataSource = self
- tableView.delegate = self
- }
-
-
- /*
- // MARK: - Navigation
-
- // In a storyboard-based application, you will often want to do a little preparation before navigation
- override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
- // Get the new view controller using segue.destination.
- // Pass the selected object to the new view controller.
- }
- */
-
-}
-
-extension DeviceViewController: UITableViewDataSource,UITableViewDelegate {
-
- func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
- return 60
- }
-
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return list.count
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
- cell.textLabel?.text = list[indexPath.row].name
- return cell
- }
-
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- let data = list[indexPath.row]
- let action = Selector(data.action)
- self.perform(action)
- }
-
-}
-
-extension DeviceViewController {
-
- @objc func eqGetAction() {
- JoyGemAIManager.shared().device.getEQMode { mode in
- debugPrint("getEQMode:\(mode)");
- } error: { err in
- debugPrint("getEQMode:\(err)");
- }
- }
-
- @objc func eqSetAction() {
- let alertController = UIAlertController(
- title: "选择操作",
- message: "请从以下选项中选择一个",
- preferredStyle: .actionSheet
- )
-
- let titles : [String] = ["普通","摇滚","流行","经典","爵士","自定义"]
- let options : [JoyGemEQMode] = [.normal,.rock,.pop,.classic,.jazz,.custom]
- for (idx,title) in titles.enumerated() {
- let action = UIAlertAction(
- title: title,
- style: .default
- ) { _ in
- // 处理选择
- JoyGemAIManager.shared().device.setEQMode(options[idx]) { err in
- debugPrint("setEQMode:\(err)");
- }
- }
- alertController.addAction(action)
- }
-
- // 添加取消按钮
- let cancelAction = UIAlertAction(title: "取消", style: .cancel, handler: nil)
- alertController.addAction(cancelAction)
-
- present(alertController, animated: true, completion: nil)
-
- }
-
- @objc func customEqGetAction() {
- JoyGemAIManager.shared().device.getCustomEQ { eq in
- debugPrint("getCustomEQ:\(eq)");
- } error: { err in
- debugPrint("getCustomEQ:\(err)");
- }
- }
-
- @objc func customEqSetAction() {
- let pickerVC = DoublePickerViewController()
- pickerVC.modalPresentationStyle = .pageSheet // 或 .formSheet
-
- pickerVC.onValuesSelected = { leftValue, rightValue in
- JoyGemAIManager.shared().device.setCustomEQ(UInt(leftValue), withGain: rightValue) { err in
- debugPrint("setCustomEQ:\(err)");
- }
- }
-
- pickerVC.onCancel = {
- print("用户取消了选择")
- }
-
- present(pickerVC, animated: true)
-
-
- }
-
- @objc func customEqResetAction() {
- JoyGemAIManager.shared().device.resetCustomEQ { err in
- debugPrint("resetCustomEQ:\(err)");
- }
- }
-
- @objc func findHeadphoneAction() {
- let alertController = UIAlertController(
- title: "选择操作",
- message: "请从以下选项中选择一个",
- preferredStyle: .actionSheet
- )
-
- let titles : [String] = ["关闭","左耳","右耳","双耳"]
- let options : [JoyGemFindHeadphoneMode] = [.cancel,.left,.right,.all]
-
- for (idx,title) in titles.enumerated() {
- let action = UIAlertAction(
- title: title,
- style: .default
- ) { _ in
- JoyGemAIManager.shared().device.findHeadphone(options[idx]) { err in
- debugPrint("findHeadphone:\(err)");
- }
- }
- alertController.addAction(action)
- }
-
- // 添加取消按钮
- let cancelAction = UIAlertAction(title: "取消", style: .cancel, handler: nil)
- alertController.addAction(cancelAction)
-
- present(alertController, animated: true, completion: nil)
-
- }
-
-}
-
-
-class DoublePickerViewController: UIViewController {
-
- var onValuesSelected: (Int, Int) -> Void = { _,_ in }
- var onCancel: () -> Void = {}
-
- // 你的两列数据
- let leftOptions = Array(stride(from: 0, through: 9, by: 1))
- let rightOptions = Array(stride(from: -12, through: 12, by: 1))
-
- private let pickerView: UIPickerView = {
- let picker = UIPickerView()
- picker.translatesAutoresizingMaskIntoConstraints = false
- return picker
- }()
-
- private let toolbar: UIToolbar = {
- let toolBar = UIToolbar()
- toolBar.translatesAutoresizingMaskIntoConstraints = false
- return toolBar
- }()
-
- override func viewDidLoad() {
- super.viewDidLoad()
- setupUI()
- }
-
- private func setupUI() {
- view.backgroundColor = .systemBackground
-
- // 配置工具栏
- let doneButton = UIBarButtonItem(title: "完成", style: .done, target: self, action: #selector(doneTapped))
- let cancelButton = UIBarButtonItem(title: "取消", style: .plain, target: self, action: #selector(cancelTapped))
- let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
-
- toolbar.items = [cancelButton, flexibleSpace, doneButton]
-
- // 配置 Picker
- pickerView.delegate = self
- pickerView.dataSource = self
-
- // 添加子视图
- view.addSubview(toolbar)
- view.addSubview(pickerView)
-
- // 设置约束
- NSLayoutConstraint.activate([
- toolbar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- toolbar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- toolbar.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- toolbar.heightAnchor.constraint(equalToConstant: 44),
-
- pickerView.topAnchor.constraint(equalTo: toolbar.bottomAnchor),
- pickerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- pickerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- pickerView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
- ])
- }
-
- @objc private func doneTapped() {
- let leftIndex = pickerView.selectedRow(inComponent: 0)
- let rightIndex = pickerView.selectedRow(inComponent: 1)
- onValuesSelected(leftOptions[leftIndex], rightOptions[rightIndex])
- dismiss(animated: true)
- }
-
- @objc private func cancelTapped() {
- onCancel()
- dismiss(animated: true)
- }
-}
-
-// 实现 PickerView 协议
-extension DoublePickerViewController: UIPickerViewDelegate, UIPickerViewDataSource {
- func numberOfComponents(in pickerView: UIPickerView) -> Int {
- return 2 // 两列
- }
-
- func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
- return component == 0 ? leftOptions.count : rightOptions.count
- }
-
- func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
- return component == 0 ? "\(leftOptions[row])" : "\(rightOptions[row])"
- }
-}
-
+++ /dev/null
-//
-// DialogueViewController.swift
-// JoyGemAIDemo
-//
-// Created by JoyGem on 2025/2/21.
-//
-
-import UIKit
-import JoyGemAI
-import AVFoundation
-
-class DialogueMessageModel {
-
- var message : String?
- var translateMessage : String?
- var current : Bool = false; //是否手机收音
-}
-
-class DialogueViewController: UIViewController {
-
- var tableView : UITableView = UITableView(frame: CGRectZero, style: UITableView.Style.grouped)
-
- var earStartButton : UIButton = UIButton(type: .custom)
-
- var earStopButton : UIButton = UIButton(type: .custom)
-
- var phoneStartButton : UIButton = UIButton(type: .custom)
-
- var phoneStopButton : UIButton = UIButton(type: .custom)
-
- var messageList : [DialogueMessageModel] = []
-
- var tmpList : [(String,UInt)] = []
-
- var tmpOtherList : [(String,UInt)] = []
-
- var otherPcm : Data = Data()
-
- override func viewDidLoad() {
- super.viewDidLoad()
- view.backgroundColor = UIColor.white
- title = "对话翻译"
-
- view.addSubview(tableView)
- tableView.snp.makeConstraints { make in
- make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
- make.leading.equalToSuperview()
- make.trailing.equalToSuperview()
- make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-120)
- }
- tableView.backgroundColor = UIColor.yellow
- tableView.delegate = self
- tableView.dataSource = self
-
- view.addSubview(phoneStartButton)
- phoneStartButton.snp.makeConstraints { make in
- make.top.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-100)
- make.centerX.equalToSuperview().multipliedBy(0.5)
- make.height.equalTo(40)
- make.width.equalTo(120)
- }
- phoneStartButton.setTitle("手机收音", for: .normal)
- phoneStartButton.setTitleColor(UIColor.darkText, for: .normal)
- phoneStartButton.addTarget(self, action: #selector(startPhoneRecord), for: .touchUpInside)
-
-// view.addSubview(phoneStopButton)
-// phoneStopButton.snp.makeConstraints { make in
-// make.top.equalTo(phoneStartButton.snp.bottom).offset(10)
-// make.centerX.equalToSuperview().multipliedBy(0.5)
-// make.height.equalTo(40)
-// make.width.equalTo(120)
-// }
-// phoneStopButton.setTitle("手机关闭收音", for: .normal)
-// phoneStopButton.setTitleColor(UIColor.darkText, for: .normal)
-// phoneStopButton.addTarget(self, action: #selector(stopPhoneRecord), for: .touchUpInside)
-
- view.addSubview(earStartButton)
- earStartButton.snp.makeConstraints { make in
- make.top.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-100)
- make.centerX.equalToSuperview().multipliedBy(1.5)
- make.height.equalTo(40)
- make.width.equalTo(120)
- }
- earStartButton.setTitle("耳机收音", for: .normal)
- earStartButton.setTitleColor(UIColor.darkText, for: .normal)
- earStartButton.addTarget(self, action: #selector(startEarRecord), for: .touchUpInside)
-
-// view.addSubview(earStopButton)
-// earStopButton.snp.makeConstraints { make in
-// make.top.equalTo(phoneStopButton.snp.top)
-// make.centerX.equalToSuperview().multipliedBy(1.5)
-// make.height.equalTo(40)
-// make.width.equalTo(120)
-// }
-// earStopButton.setTitle("耳机关闭收音", for: .normal)
-// earStopButton.setTitleColor(UIColor.darkText, for: .normal)
-// earStopButton.addTarget(self, action: #selector(stopEarRecord), for: .touchUpInside)
-
- JoyGemSIManager.shared().originalLanguage = kJoyGemAILocalizationZH
- JoyGemSIManager.shared().targetLanguage = kJoyGemAILocalizationEN
- JoyGemSIManager.shared().delegate = self
-
- JoyGemSIDeviceManager.shared().originalLanguage = kJoyGemAILocalizationEN
- JoyGemSIDeviceManager.shared().targetLanguage = kJoyGemAILocalizationZH
- JoyGemSIDeviceManager.shared().delegate = self
-
- PcmSound.sharedInstance().delegate = self;
- PcmSound.sharedInstance().setup(16000, withchannels: 1)
- do {
- try AVAudioSession.sharedInstance().setActive(true)
- } catch {
- print(error)
- }
- }
-
- @objc func startPhoneRecord() {
-
- tmpList.removeAll()
- tmpOtherList.removeAll()
- let model = DialogueMessageModel()
- model.current = true
- messageList.append(model)
- tableView.reloadData()
- JoyGemSIManager.shared().start()
- }
-
- @objc func stopPhoneRecord() {
- JoyGemSIManager.shared().stop()
- }
-
- @objc func startEarRecord() {
- tmpList.removeAll()
- tmpOtherList.removeAll()
- let model = DialogueMessageModel()
- model.current = false
- messageList.append(model)
- tableView.reloadData()
- JoyGemSIDeviceManager.shared().start()
- otherPcm = Data()
- do {
- try AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: [.defaultToSpeaker])
- try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
- } catch {
- print(error)
- }
- }
-
- @objc func stopEarRecord() {
- JoyGemSIDeviceManager.shared().stop()
- //PcmSound.sharedInstance().feed(otherPcm)
- }
-}
-
-// MARK: - UITableViewDataSource
-extension DialogueViewController: UITableViewDataSource,UITableViewDelegate {
-
- func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
- return 60
- }
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return messageList.count
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
- if (cell == nil) {
- cell = UITableViewCell(style: UITableViewCell.CellStyle.subtitle, reuseIdentifier: "cell")
- }
- let model = messageList[indexPath.row]
- cell!.textLabel?.text = model.message
- cell!.detailTextLabel?.text = model.translateMessage
- if (model.current) {
- cell!.backgroundColor = UIColor.gray
- }else {
- cell!.backgroundColor = UIColor.blue
- }
- return cell!
- }
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
-
- }
-}
-
-extension DialogueViewController : JoyGemSIManagerDelegate {
-
- func siManagerStopped(_ manager: JoyGemSIManager, reason code: JoyGemRecordStopCode) {
-
- }
-
- func siManager(_ manager: JoyGemSIManager, didUpdateRaw model: JoyGemAsrModel) {
- let msg = tmpList.firstIndex (where: { (str,idx) in
- return idx == model.index;
- })
- if (msg == nil) {
- tmpList.append((model.text,model.index))
- } else {
- tmpList[msg!] = (model.text,model.index)
- }
-
- ///监听到一句话结束,自动结束当前录音
- if (model.definite == true) {
- stopPhoneRecord()
- }
-
- guard let model = messageList.last else {
- return
- }
-
- model.message = tmpList.compactMap({ (str,idx) in
- return str
- }).joined(separator: "\n")
- tableView.reloadData()
- }
-
- func siManager(_ manager: JoyGemSIManager, didUpdateTranslate model: JoyGemAsrModel) {
- let msg = tmpOtherList.firstIndex (where: { (str,idx) in
- return idx == model.index;
- })
- if (msg == nil) {
- tmpOtherList.append((model.text,model.index))
- } else {
- tmpOtherList[msg!] = (model.text,model.index)
- }
-
- guard let model = messageList.last else {
- return
- }
-
- model.translateMessage = tmpOtherList.compactMap({ (str,idx) in
- return str
- }).joined(separator: "\n")
- tableView.reloadData()
- }
-
- func siManager(_ manager: JoyGemSIManager, saveFile path: String) {
-
- }
-
-
- func siManager(_ manager: JoyGemSIManager, stateChange code: JoyGemStateCode) {
-
- }
-
- func siManagerStopped(_ manager: JoyGemSIManager) {
-
- }
-
- func siManager(_ manager: JoyGemSIManager, didUpdateAudioData data: Data) {
- PcmSound.sharedInstance().feed(data)
- }
-
- func siManager(_ manager: JoyGemSIManager, onError code: JoyGemErrorCode) {
-
- }
-}
-
-extension DialogueViewController : JoyGemSIDeviceManagerDelegate {
-
- func siDeviceManagerStopped(_ manager: JoyGemSIDeviceManager, reason code: JoyGemRecordStopCode) {
-
- }
-
- func siDeviceManager(_ manager: JoyGemSIDeviceManager, didUpdateRaw model: JoyGemAsrModel) {
- debugPrint("text: \(model.text),index: \(model.index)")
- let msg = tmpList.firstIndex (where: { (str,idx) in
- return idx == model.index;
- })
- if (msg == nil) {
- tmpList.append((model.text,model.index))
- } else {
- tmpList[msg!] = (model.text,model.index)
- }
-
- ///监听到一句话结束,自动结束当前录音
- if (model.definite == true) {
- stopEarRecord()
- }
-
- guard let model = messageList.last else {
- return
- }
-
- model.message = tmpList.compactMap({ (str,idx) in
- return str
- }).joined(separator: "\n")
- tableView.reloadData()
- }
-
- func siDeviceManager(_ manager: JoyGemSIDeviceManager, didUpdateTranslate model: JoyGemAsrModel) {
- let msg = tmpOtherList.firstIndex (where: { (str,idx) in
- return idx == model.index;
- })
- if (msg == nil) {
- tmpOtherList.append((model.text,model.index))
- } else {
- tmpOtherList[msg!] = (model.text,model.index)
- }
-
- guard let model = messageList.last else {
- return
- }
-
- model.translateMessage = tmpOtherList.compactMap({ (str,idx) in
- return str
- }).joined(separator: "\n")
- tableView.reloadData()
- }
-
- func siDeviceManager(_ manager: JoyGemSIDeviceManager, didUpdateAudioData data: Data) {
- //otherPcm.append(data)
- PcmSound.sharedInstance().feed(data)
- }
-
- func siDeviceManager(_ manager: JoyGemSIDeviceManager, update mode: JoyGemRecordMode) {
-
- }
-
- func siDeviceManager(_ manager: JoyGemSIDeviceManager, saveFile path: String) {
- debugPrint("path: \(path)")
- }
-
- func siDeviceManager(_ manager: JoyGemSIDeviceManager, stateChange code: JoyGemStateCode) {
- debugPrint("code: \(code)")
- }
-
- func siDeviceManager(_ manager: JoyGemSIDeviceManager, onError code: JoyGemErrorCode) {
-
- }
-}
-
-
-extension DialogueViewController : PcmSoundDelegate {
-
- func remaining(_ frames: UInt) {
- debugPrint("[frame:\(frames)]");
- }
-}
+++ /dev/null
-//
-// Utils.swift
-// JoyGemAIDemo
-//
-// Created by JoyGem on 2025/2/10.
-//
-
-import Foundation
-
-extension Data {
-
- func joined(format: String = "%02x", _ separator: String = "") -> String {
- self
- .map { String(format: format, $0) }
- .joined(separator: separator)
- }
-
- func reversedJoined(format: String = "%02x", _ separator: String = "") -> String {
- self
- .map { String(format: format, $0) }
- .reversed()
- .joined(separator: separator)
- }
-
- var int: Int {
- self
- .map { Int($0) }
- .enumerated()
- .map { $1 << ($0 * 8) }
- .reduce(0, { partialResult, value in
- partialResult | value
- })
- }
-}
-
-// UInt32 和 UInt16 的扩展,用于将数字转换为 Data
-extension FixedWidthInteger {
- var data: Data {
- var value = self.littleEndian
- return Data(bytes: &value, count: MemoryLayout.size(ofValue: self))
- }
-}
-
+++ /dev/null
-<?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>UIApplicationSceneManifest</key>
- <dict>
- <key>UIApplicationSupportsMultipleScenes</key>
- <false/>
- <key>UISceneConfigurations</key>
- <dict>
- <key>UIWindowSceneSessionRoleApplication</key>
- <array>
- <dict>
- <key>UISceneConfigurationName</key>
- <string>Default Configuration</string>
- <key>UISceneDelegateClassName</key>
- <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
- <key>UISceneStoryboardFile</key>
- <string>Main</string>
- </dict>
- </array>
- </dict>
- </dict>
- <key>UIBackgroundModes</key>
- <array>
- <string>bluetooth-peripheral</string>
- <string>bluetooth-central</string>
- <string>audio</string>
- </array>
-</dict>
-</plist>
+++ /dev/null
-//
-// Use this file to import your target's public headers that you would like to expose to Swift.
-//
-
-#import "PcmSound.h"
+++ /dev/null
-//
-// ViewController.swift
-// JoyGemAIDemo
-//
-// Created by JoyGem on 2025/2/10.
-//
-
-import UIKit
-import JoyGemAI
-import CoreBluetooth
-import os.log
-import AVFoundation
-
-///主界面
-class MainViewController: UIViewController {
-
- internal var tableView: UITableView!
- private var cbManager: CBCentralManager!
- private var cbState = CBManagerState.unknown
-
- private var cbInfomations = [(CBPeripheral,[String : Any],NSNumber)]()
-
- override func viewDidLoad() {
- super.viewDidLoad()
- title = "扫描设备"
- // Do any additional setup after loading the view.
- tableView = UITableView(frame: CGRectZero, style: UITableView.Style.grouped)
- //tableView.register(UITableViewCell.classForCoder(), forCellReuseIdentifier: "peripheralCell")
- view.addSubview(tableView)
- tableView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
-
- tableView.delegate = self
- tableView.dataSource = self
- tableView.reloadData()
-
- self.navigationItem.rightBarButtonItems = [
- UIBarButtonItem(barButtonSystemItem: .refresh, target: self, action: #selector(scan)),
- ]
-
- //MARK: 初始化SDK
- JoyGemAIManager.shared().initSdk()
- //MARK: 配置日志类型
- JoyGemAIManager.shared().setLogMode(JoyGemLogMode.all)
-
- let fileManager = FileManager.default
- if let appSupportDirectory = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first {
- let logDirectory = appSupportDirectory.appendingPathComponent("log")
-
- // 检查 log 文件夹是否存在
- if !fileManager.fileExists(atPath: logDirectory.path) {
- do {
- // 创建 log 文件夹
- try fileManager.createDirectory(at: logDirectory, withIntermediateDirectories: true, attributes: nil)
- print("log 文件夹已创建: \(logDirectory.path)")
- } catch {
- print("创建 log 文件夹时出错: \(error.localizedDescription)")
- }
- } else {
- print("log 文件夹已存在: \(logDirectory.path)")
- }
-
- // 获取当前日期并格式化
- let currentDate = Date()
- let dateFormatter = DateFormatter()
- dateFormatter.dateFormat = "yyyyMMddHHmmss"
- let dateString = dateFormatter.string(from: currentDate)
-
- // 创建日志文件名和路径
- let fileName = "SDK_\(dateString).log"
- let filePath = logDirectory.appendingPathComponent(fileName)
-
- // 创建空文件
- if !fileManager.fileExists(atPath: filePath.path) {
- // 创建空文件
- fileManager.createFile(atPath: filePath.path, contents: nil, attributes: nil)
- print("日志文件已创建: \(filePath.path)")
- } else {
- print("日志文件已存在: \(filePath.path)")
- }
-
- //MARK: 配置日志路径
- JoyGemAIManager.shared().setLogPath(filePath.path)
- } else {
- print("无法找到应用支持目录")
- }
-
- //MARK: 配置缓存路径
- let tempPath = NSTemporaryDirectory();
- JoyGemAIManager.shared().setCacheDirectory(tempPath)
- JoyGemAIManager.shared().setTWSAutoSync(true)
-
- cbManager = CBCentralManager(delegate: self, queue: nil)
-
- }
-}
-
-// 扩展 String 来添加 padLeft 方法
-extension String {
- func padLeft(toLength: Int, withPad pad: String) -> String {
- let paddingCount = max(0, toLength - self.count)
- return String(repeating: pad, count: paddingCount) + self
- }
-}
-
-extension MainViewController: UITableViewDataSource,UITableViewDelegate {
-
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return cbInfomations.count
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- var cell = tableView.dequeueReusableCell(withIdentifier: "peripheralCell")
- if (cell == nil) {
- cell = UITableViewCell(style: .subtitle, reuseIdentifier: "peripheralCell")
- }
- cell!.textLabel?.text = "\(cbInfomations[indexPath.row].0.name ?? "CBPeripheral")"
-
- if let advMsd = cbInfomations[indexPath.row].1[CBAdvertisementDataManufacturerDataKey] as? Data {
- if (advMsd.count >= 13) {
- let mac = advMsd[7...12];
- cell!.detailTextLabel?.text = mac.map { String($0, radix: 16).padLeft(toLength: 2, withPad: "0") }.joined(separator: ":")
- } else {
- cell!.detailTextLabel?.text = nil;
- }
- } else {
- cell!.detailTextLabel?.text = nil;
- }
-
- return cell!
- }
-
- func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
- return 66
- }
-
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- let vc = PeripheralViewController()
- vc.cbManager = cbManager
- vc.currentPeripheral = cbInfomations[indexPath.row].0
- self.navigationController?.pushViewController(vc, animated: true)
- }
-
- @objc func scan() {
-// cbInfomations.removeAll()
-// tableView.reloadData()
-// cbManager.scanForPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
-// //cbManager.scanForPeripherals(withServices: [],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
-
-
- print(" === \(kJoyGemAIServiceUUID)")
- cbInfomations.removeAll()
- tableView.reloadData()
- cbManager.scanForPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)],options: [CBCentralManagerScanOptionAllowDuplicatesKey : false])
-
-
- let devices = cbManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: kJoyGemAIServiceUUID)])
- for item in devices {
- print(item)
- // DB209A55-DD0E-5031-29FA-40D734C34971
- // "edr:21140DE4C3D9"
- // "ble:21140D2CC682"
- let vc = PeripheralViewController()
- vc.cbManager = cbManager
- vc.currentPeripheral = item
- self.navigationController?.pushViewController(vc, animated: true)
- break
- }
- }
-}
-
-extension MainViewController: CBCentralManagerDelegate {
-
- func centralManagerDidUpdateState(_ central: CBCentralManager) {
- // In your application, you would address each possible value of central.state and central.authorization
- switch central.state {
- case .resetting:
- os_log("Connection with the system service was momentarily lost. Update imminent")
- case .unsupported:
- os_log("Platform does not support the Bluetooth Low Energy Central/Client role")
- case .unauthorized:
- switch CBManager.authorization {
- case .restricted:
- os_log("Bluetooth is restricted on this device")
- case .denied:
- os_log("The application is not authorized to use the Bluetooth Low Energy role")
- default:
- os_log("Something went wrong. Cleaning up cbManager")
- }
- case .poweredOff:
- os_log("Bluetooth is currently powered off")
- case .poweredOn:
- os_log("Starting cbManager")
- scan()
- default:
- os_log("Cleaning up cbManager")
- }
- }
-
- func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
- cbInfomations.append((peripheral,advertisementData,RSSI))
- tableView.reloadData()
- }
-
- func centralManager(_ central: CBCentralManager, connectionEventDidOccur event: CBConnectionEvent, for peripheral: CBPeripheral) {
-// os_log("connectionEventDidOccur for peripheral: %@", peripheral)
-// switch event {
-// case .peerConnected:
-// cbPeripherals.append(peripheral)
-// case .peerDisconnected:
-// os_log("Peer %@ disconnected!", peripheral)
-// default:
-// if let idx = cbPeripherals.firstIndex(where: { $0 === peripheral }) {
-// cbPeripherals.remove(at: idx)
-// }
-// }
-// tableView.reloadData()
- }
-
- func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
- os_log("peripheral: %@ connected", peripheral)
- }
-
- func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
- os_log("peripheral: %@ failed to connect", peripheral)
- }
-
- func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
- os_log("peripheral: %@ disconnected", peripheral)
- }
-}
+++ /dev/null
-//
-// OtherViewController.swift
-// JoyGemAIDemo
-//
-// Created by JoyGem on 2025/2/21.
-//
-
-import UIKit
-import JoyGemAI
-import SVProgressHUD
-
-class OtherViewController: UIViewController {
-
- internal var requestTextView : UITextView!
- internal var responseTextView : UITextView!
-
-// let content = "A:喂,你好!是小红吗?\nB: 喂,是我!你是小明吧?最近怎么样?\nA: 挺好的!最近刚忙完工作,正想放松一下。你呢?\nB: 我也还不错!刚好最近有假期,正琢磨去哪儿玩呢。\nA: 太巧了!我正想问你呢,要不要一起出去旅游?\nB: 好啊!我正愁没人一起呢。你想去哪儿?\nA: 我听说云南最近天气特别好,丽江和大理风景超美,要不要去看看?\nB: 云南啊!我一直想去!不过那边海拔高,会不会有高原反应?\nA: 应该还好,我们慢慢适应就行。而且可以先去昆明过渡一下。\nB: 有道理!那咱们计划几天?五天够吗?\nA: 五天稍微有点紧,要不七天吧?可以玩得轻松点。\nB: 行!那咱们怎么安排行程?你想自由行还是跟团?\nA: 我倾向于自由行,自己安排时间更灵活。\nB: 我也是!那我来查查机票和民宿?\nA: 好啊,你负责住宿,我来规划路线,怎么样?\nB: 没问题!对了,咱们预算大概多少?\nA: 人均四五千应该够了吧?主要是机票和住宿。\nB: 差不多,我看看有没有优惠。\nA: 好!那咱们明天再碰一下具体细节?\nB: 好的,明天见!拜拜!\nA: 拜拜!"
-
- let content = "喂,你好!\n喂,是我!最近怎么样?\n挺好的!最近刚忙完工作,正想放松一下。你呢?\n我也还不错!刚好最近有假期,正琢磨去哪儿玩呢。\n 太巧了!我正想问你呢,要不要一起出去旅游?\n好啊!我正愁没人一起呢。你想去哪儿?\n我听说云南最近天气特别好,丽江和大理风景超美,要不要去看看?\n云南啊!我一直想去!不过那边海拔高,会不会有高原反应?\n 应该还好,我们慢慢适应就行。而且可以先去昆明过渡一下。\n有道理!那咱们计划几天?五天够吗?\n五天稍微有点紧,要不七天吧?可以玩得轻松点。\n行!那咱们怎么安排行程?你想自由行还是跟团?\n 我倾向于自由行,自己安排时间更灵活。\n我也是!那我来查查机票和民宿?\n好啊,你负责住宿,我来规划路线,怎么样?\n没问题!对了,咱们预算大概多少?\n人均四五千应该够了吧?主要是机票和住宿。\n 差不多,我看看有没有优惠。\n好!那咱们明天再碰一下具体细节?\n好的,明天见!拜拜!\n拜拜!"
-
- deinit {
- cancelAction()
- }
-
- override func viewDidLoad() {
- super.viewDidLoad()
- view.backgroundColor = .white
- title = "其它"
-
- self.navigationItem.rightBarButtonItems = [
- UIBarButtonItem(title: "翻译", style: .done, target: self, action: #selector(translateAction)),
- UIBarButtonItem(title: "摘要", style: .done, target: self, action: #selector(summaryAction)),
- UIBarButtonItem(title: "取消", style: .done, target: self, action: #selector(cancelAction))
- ]
-
- requestTextView = UITextView()
- view.addSubview(requestTextView)
- requestTextView.backgroundColor = UIColor.gray
- requestTextView.snp.makeConstraints { make in
- make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
- make.leading.trailing.equalToSuperview()
- make.bottom.equalTo(view.snp.centerY).offset(-50)
- }
- responseTextView = UITextView()
- view.addSubview(responseTextView)
- responseTextView.backgroundColor = UIColor.yellow
- responseTextView.snp.makeConstraints { make in
- make.leading.trailing.equalToSuperview()
- make.top.equalTo(requestTextView.snp.bottom)
- make.height.equalTo(requestTextView.snp.height)
- }
- requestTextView.text = content
- }
-
- @objc func summaryAction() {
-
- responseTextView.text = nil
- JoyGemAIManager.shared().cancelSummaryRequest()
-
- SVProgressHUD.show()
- JoyGemAIManager.shared().summary(requestTextView.text) {[weak self] text, finish in
- guard let self = self else{return}
- self.responseTextView.text += text
- if (finish) {
- SVProgressHUD.dismiss()
- }
- } error: {[weak self] error in
- guard let self = self else{return}
- SVProgressHUD.dismiss()
- self.responseTextView.text = error.debugDescription
- }
-
- }
- @objc func translateAction() {
-
- responseTextView.text = nil
- JoyGemAIManager.shared().cancelTranslateRequest()
-
- SVProgressHUD.show()
- JoyGemAIManager.shared().translate(requestTextView.text, from: kJoyGemAILocalizationZH, to: kJoyGemAILocalizationEN) {[weak self] text, finish in
- guard let self = self else{return}
- self.responseTextView.text += text
- if (finish) {
- SVProgressHUD.dismiss()
- }
- } error: {[weak self] error in
- guard let self = self else{return}
- SVProgressHUD.dismiss()
- self.responseTextView.text = error.debugDescription
- }
- }
-
- @objc func cancelAction() {
- JoyGemAIManager.shared().cancelSummaryRequest()
- JoyGemAIManager.shared().cancelTranslateRequest()
- }
-
-}
+++ /dev/null
-
-
-#import <Foundation/Foundation.h>
-
-#define NAMESPACE @"pcm_sound"
-
-@protocol PcmSoundDelegate <NSObject>
-
--(void)remaining:(NSUInteger)frames;
-
-@end
-
-@interface PcmSound : NSObject
-
-+ (PcmSound*)sharedInstance;
-
-@property(nonatomic,weak) id<PcmSoundDelegate> delegate;
-
--(BOOL)isPlaying;
-
--(void)setLogLevel:(NSNumber*)logLevelNumber;
-
--(void)setup:(int)sampleRate withchannels:(int)numChannels;
-
--(void)feed:(NSData*)buffer;
-
--(void)setFeedThreshold:(NSNumber*)feedThreshold;
-
--(void)stopAudioUnit;
-
-- (void)cleanup;
-
-@end
+++ /dev/null
-#import "PcmSound.h"
-#import <AudioToolbox/AudioToolbox.h>
-
-#if TARGET_OS_IOS
-#import <AVFoundation/AVFoundation.h>
-#endif
-
-#define kOutputBus 0
-#define NAMESPACE @"pcm_sound" // Assuming this is the namespace you want
-
-typedef NS_ENUM(NSUInteger, LogLevel) {
- none = 0,
- error = 1,
- standard = 2,
- verbose = 3,
-};
-
-@interface PcmSound ()
-@property(nonatomic) LogLevel mLogLevel;
-@property(nonatomic) AudioComponentInstance mAudioUnit;
-@property(nonatomic) NSMutableData *mSamples;
-@property(nonatomic) int mNumChannels;
-@property(nonatomic) int mFeedThreshold;
-@property(nonatomic) bool mDidInvokeFeedCallback;
-@end
-
-@implementation PcmSound
-
-+ (instancetype)sharedInstance {
- static PcmSound *sharedInstance = nil;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- sharedInstance = [[self alloc] init];
- sharedInstance.mLogLevel = verbose;
- sharedInstance.mSamples = [NSMutableData new];
- sharedInstance.mFeedThreshold = 0;
- sharedInstance.mDidInvokeFeedCallback = false;
- });
- return sharedInstance;
-}
-
-- (instancetype)init
-{
- self = [super init];
- if (self) {
-
- }
- return self;
-}
-
--(void)dealloc {
-
-}
-
--(void)setLogLevel:(NSNumber*)logLevelNumber {
- self.mLogLevel = (LogLevel)[logLevelNumber integerValue];
-}
-
--(void)setup:(int)sampleRate withchannels:(int)numChannels {
-
- self.mNumChannels = numChannels;
-
- // cleanup
- if (_mAudioUnit != nil) {
- [self cleanup];
- }
-
- // create
- AudioComponentDescription desc;
- desc.componentType = kAudioUnitType_Output;
-#if TARGET_OS_IOS
- desc.componentSubType = kAudioUnitSubType_RemoteIO;
-#else // MacOS
- desc.componentSubType = kAudioUnitSubType_DefaultOutput;
-#endif
- desc.componentFlags = 0;
- desc.componentFlagsMask = 0;
- desc.componentManufacturer = kAudioUnitManufacturer_Apple;
-
- AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc);
- OSStatus status = AudioComponentInstanceNew(inputComponent, &_mAudioUnit);
- if (status != noErr) {
- //NSString* message = [NSString stringWithFormat:@"AudioComponentInstanceNew failed. OSStatus: %@", @(status)];
- return;
- }
-
- // set stream format
- AudioStreamBasicDescription audioFormat;
- audioFormat.mSampleRate = sampleRate;
- audioFormat.mFormatID = kAudioFormatLinearPCM;
- audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
- audioFormat.mFramesPerPacket = 1;
- audioFormat.mChannelsPerFrame = self.mNumChannels;
- audioFormat.mBitsPerChannel = 16;
- audioFormat.mBytesPerFrame = self.mNumChannels * (audioFormat.mBitsPerChannel / 8);
- audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket;
-
- status = AudioUnitSetProperty(_mAudioUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Input,
- kOutputBus,
- &audioFormat,
- sizeof(audioFormat));
- if (status != noErr) {
- //NSString* message = [NSString stringWithFormat:@"AudioUnitSetProperty StreamFormat failed. OSStatus: %@", @(status)];
- return;
- }
-
- // set callback
- AURenderCallbackStruct callback;
- callback.inputProc = RenderCallback;
- callback.inputProcRefCon = (__bridge void *)(self);
-
- status = AudioUnitSetProperty(_mAudioUnit,
- kAudioUnitProperty_SetRenderCallback,
- kAudioUnitScope_Global,
- kOutputBus,
- &callback,
- sizeof(callback));
- if (status != noErr) {
- //NSString* message = [NSString stringWithFormat:@"AudioUnitSetProperty SetRenderCallback failed. OSStatus: %@", @(status)];
- return;
- }
-
- // initialize
- status = AudioUnitInitialize(_mAudioUnit);
- if (status != noErr) {
- //NSString* message = [NSString stringWithFormat:@"AudioUnitInitialize failed. OSStatus: %@", @(status)];
- return;
- }
-}
-
--(void)feed:(NSData*)buffer {
-
- @synchronized (self.mSamples) {
- [self.mSamples appendData:buffer];
- }
-
- // reset
- self.mDidInvokeFeedCallback = false;
-
- // start playback if we can
- if (_mAudioUnit != nil) {
- UInt32 isPlaying = 0;
- UInt32 size = sizeof(isPlaying);
- OSStatus status = AudioUnitGetProperty(_mAudioUnit,
- kAudioOutputUnitProperty_IsRunning,
- kAudioUnitScope_Global,
- 0,
- &isPlaying,
- &size);
- if (status != noErr) {
- //NSString* message = [NSString stringWithFormat:@"AudioUnitGetProperty IsRunning failed. OSStatus: %@", @(status)];
- return;
- }
- if (!isPlaying) {
- status = AudioOutputUnitStart(_mAudioUnit);
- if (status != noErr) {
- //NSString* message = [NSString stringWithFormat:@"AudioOutputUnitStart failed. OSStatus: %@", @(status)];
- return;
- }
- }
- }
-}
-
--(void)setFeedThreshold:(NSNumber*)feedThreshold {
- self.mFeedThreshold = [feedThreshold intValue];
-}
-
--(BOOL)isPlaying {
- return self.mSamples.length > 0;
-}
-
-
-- (void)cleanup
-{
- if (_mAudioUnit != nil) {
- AudioUnitUninitialize(_mAudioUnit);
- AudioComponentInstanceDispose(_mAudioUnit);
- _mAudioUnit = nil;
- }
- @synchronized (self.mSamples) {
- self.mSamples = [NSMutableData new];
- }
-}
-
-- (void)stopAudioUnit
-{
- if (_mAudioUnit != nil) {
- UInt32 isRunning = 0;
- UInt32 size = sizeof(isRunning);
- OSStatus status = AudioUnitGetProperty(_mAudioUnit,
- kAudioOutputUnitProperty_IsRunning,
- kAudioUnitScope_Global,
- 0,
- &isRunning,
- &size);
- if (status != noErr) {
- NSLog(@"AudioUnitGetProperty IsRunning failed. OSStatus: %@", @(status));
- return;
- }
- if (isRunning) {
- status = AudioOutputUnitStop(_mAudioUnit);
- if (status != noErr) {
- NSLog(@"AudioOutputUnitStop failed. OSStatus: %@", @(status));
- } else {
- NSLog(@"AudioUnit stopped because no more samples");
- }
- }
- }
-}
-
-
-static OSStatus RenderCallback(void *inRefCon,
- AudioUnitRenderActionFlags *ioActionFlags,
- const AudioTimeStamp *inTimeStamp,
- UInt32 inBusNumber,
- UInt32 inNumberFrames,
- AudioBufferList *ioData)
-{
- PcmSound *instance = (__bridge PcmSound *)(inRefCon);
-
- NSUInteger remainingFrames;
- BOOL shouldRequestMore = false;
-
- @synchronized (instance.mSamples) {
-
- // clear
- memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize);
-
- NSUInteger bytesToCopy = MIN(ioData->mBuffers[0].mDataByteSize, [instance.mSamples length]);
-
- // provide samples
- memcpy(ioData->mBuffers[0].mData, [instance.mSamples bytes], bytesToCopy);
-
- // pop front bytes
- NSRange range = NSMakeRange(0, bytesToCopy);
- [instance.mSamples replaceBytesInRange:range withBytes:NULL length:0];
-
- remainingFrames = [instance.mSamples length] / (instance.mNumChannels * sizeof(short));
-
- // should request more frames?
- shouldRequestMore = remainingFrames <= instance.mFeedThreshold && !instance.mDidInvokeFeedCallback;
- }
-
- // stop running, if needed
- if (remainingFrames == 0) {
- dispatch_async(dispatch_get_main_queue(), ^{
- [instance stopAudioUnit];
- });
- }
-
- if (shouldRequestMore) {
- instance.mDidInvokeFeedCallback = true;
- //NSDictionary *response = @{@"remaining_frames": @(remainingFrames)};
- dispatch_async(dispatch_get_main_queue(), ^{
- if ([instance.delegate respondsToSelector:@selector(remaining:)]) {
- [instance.delegate remaining:remainingFrames];
- }
- });
- }
-
- return noErr;
-}
-
-
-@end
+++ /dev/null
-/*
-See the LICENSE.txt file for this sample’s licensing information.
-
-Abstract:
-A class to view details of a CBPeripheral.
-*/
-
-import CoreBluetooth
-import UIKit
-import os.log
-import AVFoundation
-import JoyGemAI
-import SVProgressHUD
-
-///设备功能界面
-class PeripheralViewController: UIViewController {
-
- let list:[(name:String,action:String)] = [
- ("AI对话","chatAction"),
- ("现场录音","recordAction"),
- ("通话录音(单声道)","callAction"),
- ("通话录音(立体声)","stereoCallAction"),
- ("同声传译","siAction"),
- ("对话翻译","dialogueAction"),
- ("配置","configAction"),
- ("设备","deviceAction"),
- ("其它","otherAction"),
- ]
-
- var tableView: UITableView!
- var cbManager: CBCentralManager?
-
- var currentPeripheral: CBPeripheral?
-
- var writeCha : CBCharacteristic?
-
- override func viewDidLoad() {
- super.viewDidLoad()
- title = "功能列表"
-
- self.navigationController?.navigationBar.tintColor = UIColor.black
-
- tableView = UITableView(frame: CGRectZero, style: UITableView.Style.grouped)
- tableView.register(UITableViewCell.classForCoder(), forCellReuseIdentifier: "cell")
- view.addSubview(tableView)
- tableView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
- tableView.dataSource = self
- tableView.delegate = self
-
- // Set peripheral delegate
- currentPeripheral?.delegate = self
- cbManager?.delegate = self
-
- cbManager?.connect(currentPeripheral!, options: [CBConnectPeripheralOptionEnableTransportBridgingKey:true])
- SVProgressHUD.show(withStatus: "连接中")
-
- JoyGemAIManager.shared().delegate = self;
- JoyGemAIManager.shared().dataSource = self;
-
- }
-
- // 自定义日期格式化器(静态实例提升性能)
- private let dateFormatter: DateFormatter = {
- let formatter = DateFormatter()
- formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
- return formatter
- }()
-}
-
-extension PeripheralViewController : JoyGemAIManagerDelegate {
-
-
- func joyGemAuthFailedCallback() {
- SVProgressHUD.showInfo(withStatus: "鉴权失败")
- }
-
- func joyGemAuthSuccessCallback() {
- SVProgressHUD.showInfo(withStatus: "鉴权成功")
- PcmSound.sharedInstance().setup(16000, withchannels: 1)
- let options: AVAudioSession.CategoryOptions = [.allowBluetooth]
- do {
- try AVAudioSession.sharedInstance().setCategory(.playback, options: [options])
- try AVAudioSession.sharedInstance().setActive(true)
- } catch {
- print(error)
- }
- }
-
- func joyGemAction(_ action: JoyGemActionMode) {
- switch action {
- case .cancel:
- SVProgressHUD.showInfo(withStatus: "请求关闭录音功能/通知关闭了对话")
- case .recordLive:
- SVProgressHUD.showInfo(withStatus: "请求开启现场录音")
- case .recordCall:
- SVProgressHUD.showInfo(withStatus: "请求开启通话录音")
- case .si:
- SVProgressHUD.showInfo(withStatus: "请求开启同声传译")
- case .chat:
- SVProgressHUD.showInfo(withStatus: "通知开启了AI对话")
- @unknown default:
- break
- }
-
- }
-}
-
-
-//MARK: 蓝牙发送时需要
-extension PeripheralViewController : JoyGemAIManagerDataSource {
-
- func joyGemSend(_ data: Data, with characteristic: CBCharacteristic) {
- if (self.currentPeripheral != nil) {
- self.currentPeripheral?.writeValue(data, for: characteristic, type: CBCharacteristicWriteType.withoutResponse)
- }
- }
-}
-
-
-extension PeripheralViewController: UITableViewDataSource,UITableViewDelegate {
-
- func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
- return 60
- }
-
- func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- return list.count
- }
-
- func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
- cell.textLabel?.text = list[indexPath.row].name
- return cell
- }
-
- func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- let data = list[indexPath.row]
- let action = Selector(data.action)
- self.perform(action)
- }
-
- func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
- return "确保鉴权成功弹出以后再进入功能界面"
- }
-
-}
-
-extension PeripheralViewController: CBCentralManagerDelegate {
-
- func centralManagerDidUpdateState(_ central: CBCentralManager) {
-
- }
-
- func debugLog(_ items: Any..., separator: String = " ", terminator: String = "\n") {
- let timestamp = dateFormatter.string(from: Date())
- let prefix = "[\(timestamp)]"
- debugPrint(prefix, items, separator: separator, terminator: terminator)
- }
-
- func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
- debugLog("蓝牙连接成功")
- peripheral.discoverServices([CBUUID(string: kJoyGemAIServiceUUID)]);
- SVProgressHUD.show(withStatus: "鉴权中")
- }
-
- func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
- os_log("peripheral: %@ failed to connect", peripheral)
- SVProgressHUD.dismiss()
- }
-
- func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
- //MARK: 设备断开连接时需要
- JoyGemAIManager.shared().bleDisConnected();
- SVProgressHUD.showError(withStatus: "蓝牙断开")
- }
-}
-
-extension PeripheralViewController: CBPeripheralDelegate {
-
- func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
-
- debugLog("发现服务成功")
- for service in peripheral.services! {
- os_log("peripheral service: %@", service)
- peripheral.discoverCharacteristics(nil, for: service)
- }
-
- }
-
- func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
-
- //MARK: 需要配置服务对象
- if (service.uuid.uuidString == kJoyGemAIServiceUUID) {
- let success = JoyGemAIManager.shared().configService(service) { chars in
- for char in chars {
- debugPrint(char)
- peripheral.setNotifyValue(true, for: char)
- }
- }
- if (!success) {
- debugPrint("初始化失败!")
- }
- }
- }
-
- func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: (any Error)?) {
- if (characteristic.isNotifying == true && characteristic.service?.uuid.uuidString == kJoyGemAIServiceUUID && characteristic.uuid.uuidString == kJoyGemAICharacteristicNotifyUUID) {
- //MARK: 使能成功时需要
- debugLog("特征使能成功")
- JoyGemAIManager.shared().bleConnected()
- }
- }
-
- func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
- //MARK: 需要配置传入数据
- JoyGemAIManager.shared().receiveValue(characteristic)
- }
-
- func peripheral(_ peripheral: CBPeripheral, didModifyServices invalidatedServices: [CBService]) {
- // Accessory's GATT database has updated. Refresh your local cache (if any)
- }
-
- func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: (any Error)?) {
-
- }
-
-}
-
-extension PeripheralViewController {
-
- @objc func recordAction() {
- //currentPeripheral?.discoverServices([CBUUID(string: kJoyGemAIServiceUUID)]);
- let vc = RecordViewController()
- self.navigationController?.pushViewController(vc, animated: true)
- }
-
- @objc func callAction() {
- guard JoyGemCallManager.shared().supportStereo == false else {
- SVProgressHUD.showError(withStatus: "该设备为立体声设备")
- return
- }
- let vc = CallViewController()
- self.navigationController?.pushViewController(vc, animated: true)
- }
-
- @objc func stereoCallAction() {
- guard JoyGemCallManager.shared().supportStereo == true else {
- SVProgressHUD.showError(withStatus: "该设备不支持立体声")
- return
- }
- let vc = StereoCallViewController()
- self.navigationController?.pushViewController(vc, animated: true)
- }
-
- @objc func chatAction() {
- let vc = ChatViewController()
- self.navigationController?.pushViewController(vc, animated: true)
- }
-
- @objc func siAction() {
- let vc = SIViewController()
- self.navigationController?.pushViewController(vc, animated: true)
- }
-
- @objc func dialogueAction() {
- let vc = DialogueViewController()
- self.navigationController?.pushViewController(vc, animated: true)
- }
-
- @objc func otherAction() {
- let vc = OtherViewController()
- self.navigationController?.pushViewController(vc, animated: true)
- }
-
- @objc func configAction() {
- let vc = ConfigViewController()
- self.navigationController?.pushViewController(vc, animated: true)
- }
-
- @objc func deviceAction() {
- let vc = DeviceViewController()
- self.navigationController?.pushViewController(vc, animated: true)
- }
-}
-
+++ /dev/null
-//
-// RecordCallViewController.swift
-// JoyGemAIPod
-//
-// Created by jjjs on 2025/5/6.
-//
-
-import UIKit
-import SnapKit
-import JoyGemAI
-import AVFoundation
-import SVProgressHUD
-
-
-class RecordCallViewController: UIViewController {
-
- var textView : UITextView!
-
- var startButton : UIButton!
-
- var stopButton : UIButton!
-
- var messageList : [(String,UInt)] = []
-
- var recordFilePath : String?
-
- override func viewDidLoad() {
- super.viewDidLoad()
- view.backgroundColor = UIColor.white
- title = "通话录音"
-
- self.navigationController?.navigationBar.tintColor = UIColor.black
- self.navigationItem.rightBarButtonItems = [
- UIBarButtonItem(title: "播放录音", style: .done, target: self, action: #selector(playRecord))
- ]
-
- textView = UITextView()
- view.addSubview(textView)
- textView.snp.makeConstraints { make in
- make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
- make.leading.trailing.equalToSuperview()
- make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-100)
- }
- textView.backgroundColor = UIColor.gray
- startButton = UIButton(type: .custom)
- view.addSubview(startButton)
- startButton.snp.makeConstraints { make in
- make.top.equalTo(textView.snp.bottom).offset(20)
- make.centerX.equalToSuperview().multipliedBy(0.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- startButton.setTitle("开始", for: .normal)
- startButton.setTitleColor(UIColor.darkText, for: .normal)
- startButton.addTarget(self, action: #selector(startRecord), for: .touchUpInside)
-
- stopButton = UIButton(type: .custom)
- view.addSubview(stopButton)
- stopButton.snp.makeConstraints { make in
- make.top.equalTo(textView.snp.bottom).offset(20)
- make.centerX.equalToSuperview().multipliedBy(1.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- stopButton.setTitle("结束", for: .normal)
- stopButton.setTitleColor(UIColor.darkText, for: .normal)
- stopButton.addTarget(self, action: #selector(endRecord), for: .touchUpInside)
-
- // Do any additional setup after loading the view.
- JoyGemCallManager.shared().delegate = self
- }
-
- @objc func startRecord() {
- messageList.removeAll()
- textView.text = nil
- JoyGemCallManager.shared().start()
- }
-
- @objc func endRecord() {
- JoyGemCallManager.shared().stop()
- }
-
- var audioPlayer: AVAudioPlayer?
-
- ///播放最后一次录音文件
- @objc func playRecord() {
- guard let file = recordFilePath else {return;}
-
- do {
- // 创建 AVAudioPlayer 实例
- audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: file))
- audioPlayer?.prepareToPlay() // 准备播放
- audioPlayer?.play() // 播放音频
- } catch {
- debugPrint("播放音频时发生错误: \(error.localizedDescription)")
- }
- }
-
-}
-
-extension RecordCallViewController : JoyGemCallManagerDelegate {
-
- func callManagerStopped(_ manager: JoyGemCallManager, reason code: JoyGemRecordStopCode) {
- if (code == .actively) {
- SVProgressHUD.showInfo(withStatus: "用户主动结束")
- } else {
- SVProgressHUD.showInfo(withStatus: "自动结束")
- ///判断当前蓝牙是否连接从而确定是否因为蓝牙断开造成的录音断开
- }
- }
-
- func callManagerNotonCall(_ manager: JoyGemCallManager) {
- SVProgressHUD.showInfo(withStatus: "未处于通话状态")
- }
-
- func callManager(_ manager: JoyGemCallManager, saveFile path: String) {
- debugPrint("path: \(path)")
- recordFilePath = path
- }
-
- func callManager(_ manager: JoyGemCallManager, stateChange code: JoyGemStateCode) {
- debugPrint("code: \(code)")
- }
-
- func callManager(_ manager: JoyGemCallManager, onError code: JoyGemErrorCode) {
-
- }
-
- func callManager(_ manager: JoyGemCallManager, didUpdateAsr model: JoyGemAsrModel) {
- debugPrint("text: \(model.text),index: \(model.index)")
- let msg = messageList.firstIndex (where: { (str,idx) in
- return idx == model.index;
- })
- if (msg == nil) {
- messageList.append((model.text,model.index))
- } else {
- messageList[msg!] = (model.text,model.index)
- }
-
- textView.text = messageList.compactMap({ (str,idx) in
- return str
- }).joined(separator: "\n")
- }
-
- func callManagerCompleted(_ manager: JoyGemCallManager) {
- debugPrint("数据已全部接收")
- }
-}
-
-
+++ /dev/null
-//
-// RecordViewController.swift
-// JoyGemAIDemo
-//
-// Created by JoyGem on 2025/2/21.
-//
-
-import UIKit
-import SnapKit
-import JoyGemAI
-import AVFoundation
-import SVProgressHUD
-
-//录音界面
-class RecordViewController: UIViewController {
-
- var textView : UITextView!
-
- var startButton : UIButton = UIButton(type: .custom)
-
- var stopButton : UIButton = UIButton(type: .custom)
-
- var pauseButton : UIButton = UIButton(type: .custom)
-
- var resumeButton : UIButton = UIButton(type: .custom)
-
- var messageList : [(String,UInt)] = []
-
- var recordFilePath : String?
-
- override func viewDidLoad() {
- super.viewDidLoad()
- view.backgroundColor = UIColor.white
- title = "录音"
-
- self.navigationController?.navigationBar.tintColor = UIColor.black
- self.navigationItem.rightBarButtonItems = [
- UIBarButtonItem(title: "播放录音", style: .done, target: self, action: #selector(playRecord))
- ]
-
- textView = UITextView()
- view.addSubview(textView)
- textView.snp.makeConstraints { make in
- make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
- make.leading.trailing.equalToSuperview()
- make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-200)
- }
- textView.backgroundColor = UIColor.gray
-
- view.addSubview(startButton)
- startButton.snp.makeConstraints { make in
- make.top.equalTo(textView.snp.bottom).offset(20)
- make.centerX.equalToSuperview().multipliedBy(0.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- startButton.setTitle("开始", for: .normal)
- startButton.setTitleColor(UIColor.darkText, for: .normal)
- startButton.addTarget(self, action: #selector(startRecord), for: .touchUpInside)
-
- view.addSubview(stopButton)
- stopButton.snp.makeConstraints { make in
- make.top.equalTo(textView.snp.bottom).offset(20)
- make.centerX.equalToSuperview().multipliedBy(1.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- stopButton.setTitle("结束", for: .normal)
- stopButton.setTitleColor(UIColor.darkText, for: .normal)
- stopButton.addTarget(self, action: #selector(endRecord), for: .touchUpInside)
-
- view.addSubview(pauseButton)
- pauseButton.snp.makeConstraints { make in
- make.top.equalTo(textView.snp.bottom).offset(120)
- make.centerX.equalToSuperview().multipliedBy(0.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- pauseButton.setTitle("暂停", for: .normal)
- pauseButton.setTitleColor(UIColor.darkText, for: .normal)
- pauseButton.addTarget(self, action: #selector(pauseRecord), for: .touchUpInside)
-
- view.addSubview(resumeButton)
- resumeButton.snp.makeConstraints { make in
- make.top.equalTo(textView.snp.bottom).offset(120)
- make.centerX.equalToSuperview().multipliedBy(1.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- resumeButton.setTitle("继续", for: .normal)
- resumeButton.setTitleColor(UIColor.darkText, for: .normal)
- resumeButton.addTarget(self, action: #selector(resumeRecord), for: .touchUpInside)
-
- // Do any additional setup after loading the view.
- JoyGemRecordManager.shared().delegate = self
-
- PcmSound.sharedInstance().delegate = self;
- PcmSound.sharedInstance().setup(16000, withchannels: 1)
- let options: AVAudioSession.CategoryOptions = [.allowBluetooth]
- do {
- try AVAudioSession.sharedInstance().setCategory(.playback, options: [options])
- try AVAudioSession.sharedInstance().setActive(true)
- } catch {
- print(error)
- }
- }
-
- @objc func startRecord() {
- messageList.removeAll()
- textView.text = nil
- JoyGemRecordManager.shared().originalLanguage = kJoyGemAILocalizationZH
- JoyGemRecordManager.shared().start()
- }
-
- @objc func endRecord() {
- JoyGemRecordManager.shared().stop()
- }
-
- @objc func pauseRecord() {
- JoyGemRecordManager.shared().pause()
- }
-
- @objc func resumeRecord() {
- JoyGemRecordManager.shared().resume()
- }
-
- var audioPlayer: AVAudioPlayer?
-
- ///播放最后一次录音文件
- @objc func playRecord() {
- guard let file = recordFilePath else {return;}
-
- do {
- // 创建 AVAudioPlayer 实例v
- audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: file))
- audioPlayer?.prepareToPlay() // 准备播放
- audioPlayer?.play() // 播放音频
- } catch {
- debugPrint("播放音频时发生错误: \(error.localizedDescription)")
- }
- }
-
-}
-
-extension RecordViewController : JoyGemRecordManagerDelegate {
-
- func recordManager(_ manager: JoyGemRecordManager, didUpdateAudioData data: Data) {
- PcmSound.sharedInstance().feed(data)
- }
-
- func recordManager(_ manager: JoyGemRecordManager, didUpdateTranslate model: JoyGemAsrModel) {
-
- }
-
- func recordManager(_ manager: JoyGemRecordManager, didUpdateAsr model: JoyGemAsrModel) {
- debugPrint("text: \(model.text),index: \(model.index)")
- let msg = messageList.firstIndex (where: { (str,idx) in
- return idx == model.index;
- })
- if (msg == nil) {
- messageList.append((model.text,model.index))
- } else {
- messageList[msg!] = (model.text,model.index)
- }
-
- textView.text = messageList.compactMap({ (str,idx) in
- return str
- }).joined(separator: "\n")
- }
-
-
- func recordManager(_ manager: JoyGemRecordManager, update mode: JoyGemRecordMode) {
- debugPrint("mode: \(mode)")
- }
-
- func recordManager(_ manager: JoyGemRecordManager, saveFile path: String) {
- debugPrint("path: \(path)")
- recordFilePath = path
- }
-
- func recordManager(_ manager: JoyGemRecordManager, stateChange code: JoyGemStateCode) {
- debugPrint("code: \(code)")
- }
-
-
- func recordManagerStopped(_ manager: JoyGemRecordManager, reason code: JoyGemRecordStopCode) {
- if (code == .actively) {
- SVProgressHUD.showInfo(withStatus: "用户主动结束")
- } else {
- SVProgressHUD.showInfo(withStatus: "自动结束")
- ///判断当前蓝牙是否连接从而确定是否因为蓝牙断开造成的录音断开
- }
- }
-
- func recordManager(_ manager: JoyGemRecordManager, onError code: JoyGemErrorCode) {
-
- }
-}
-
-extension RecordViewController : PcmSoundDelegate {
-
- func remaining(_ frames: UInt) {
- debugPrint("[frame:\(frames)]");
- }
-}
-
+++ /dev/null
-//
-// SIViewController.swift
-// JoyGemAIDemo
-//
-// Created by JoyGem on 2025/2/21.
-//
-
-import UIKit
-import JoyGemAI
-import AVFoundation
-import SVProgressHUD
-
-class SIViewController: UIViewController {
-
- var textView : UITextView!
- var translateTextView : UITextView!
-
- var startButton : UIButton!
-
- var stopButton : UIButton!
-
- var messageList : [(String,UInt)] = []
-
- var translateList : [(String,UInt)] = []
-
- var recordFilePath : String?
-
- override func viewDidLoad() {
- super.viewDidLoad()
- view.backgroundColor = UIColor.white
- title = "同声传译"
-
- self.navigationController?.navigationBar.tintColor = UIColor.black
- self.navigationItem.rightBarButtonItems = [
- UIBarButtonItem(title: "播放录音", style: .done, target: self, action: #selector(playRecord))
- ]
-
- textView = UITextView()
- view.addSubview(textView)
- textView.backgroundColor = UIColor.gray
- textView.snp.makeConstraints { make in
- make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
- make.leading.trailing.equalToSuperview()
- make.bottom.equalTo(view.snp.centerY).offset(-50)
- }
- translateTextView = UITextView()
- view.addSubview(translateTextView)
- translateTextView.backgroundColor = UIColor.yellow
- translateTextView.snp.makeConstraints { make in
- make.leading.trailing.equalToSuperview()
- make.top.equalTo(textView.snp.bottom)
- make.height.equalTo(textView.snp.height)
- }
-
- startButton = UIButton(type: .custom)
- view.addSubview(startButton)
- startButton.snp.makeConstraints { make in
- make.top.equalTo(translateTextView.snp.bottom).offset(20)
- make.centerX.equalToSuperview().multipliedBy(0.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- startButton.setTitle("开始", for: .normal)
- startButton.setTitleColor(UIColor.darkText, for: .normal)
- startButton.addTarget(self, action: #selector(startRecord), for: .touchUpInside)
-
- stopButton = UIButton(type: .custom)
- view.addSubview(stopButton)
- stopButton.snp.makeConstraints { make in
- make.top.equalTo(translateTextView.snp.bottom).offset(20)
- make.centerX.equalToSuperview().multipliedBy(1.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- stopButton.setTitle("结束", for: .normal)
- stopButton.setTitleColor(UIColor.darkText, for: .normal)
- stopButton.addTarget(self, action: #selector(endRecord), for: .touchUpInside)
-
- // Do any additional setup after loading the view.
- JoyGemSIManager.shared().delegate = self
-
- PcmSound.sharedInstance().delegate = self;
- do {
- try AVAudioSession.sharedInstance().setCategory(.playback)
- try AVAudioSession.sharedInstance().setActive(true)
- } catch {
- print(error)
- }
- PcmSound.sharedInstance().setup(16000, withchannels: 1)
-
-
- }
-
- @objc func startRecord() {
- messageList.removeAll()
- translateList.removeAll()
- textView.text = nil
- translateTextView.text = nil
-
- if Thread.isMainThread {
- do {
- try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [])
- try AVAudioSession.sharedInstance().setActive(true)
- } catch let error as NSError {
- print("An error occurred setting the audio session category: \(error.localizedDescription)")
- }
- } else {
- DispatchQueue.main.sync {
- do {
- try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [])
- try AVAudioSession.sharedInstance().setActive(true)
- } catch let error as NSError {
- print("An error occurred setting the audio session category: \(error.localizedDescription)")
- }
- }
- }
-
-
-// do {
-// try AVAudioSession.sharedInstance().setCategory(.playAndRecord)
-// try AVAudioSession.sharedInstance().setActive(true)
-// } catch {
-// print(error)
-// }
-
-// try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord, mode: .default)
-// try? AVAudioSession.sharedInstance().setActive(true)
- JoyGemSIManager.shared().originalLanguage = kJoyGemAILocalizationZH
- JoyGemSIManager.shared().targetLanguage = kJoyGemAILocalizationJA
- JoyGemSIManager.shared().start()
- }
-
- @objc func endRecord() {
- JoyGemSIManager.shared().stop()
- }
-
- var audioPlayer: AVAudioPlayer?
-
- ///播放最后一次录音文件
- @objc func playRecord() {
- guard let file = recordFilePath else {return;}
- do {
- // 创建 AVAudioPlayer 实例v
-
- audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: file))
- audioPlayer?.prepareToPlay() // 准备播放
- audioPlayer?.play() // 播放音频
- } catch {
- debugPrint("播放音频时发生错误: \(error.localizedDescription)")
- }
- }
-}
-
-extension SIViewController : JoyGemSIManagerDelegate {
-
- func siManagerStopped(_ manager: JoyGemSIManager, reason code: JoyGemRecordStopCode) {
- if (code == .actively) {
- SVProgressHUD.showInfo(withStatus: "用户主动结束")
- } else {
- SVProgressHUD.showInfo(withStatus: "用户被动结束")
- }
- }
-
- func siManager(_ manager: JoyGemSIManager, didUpdateRaw model: JoyGemAsrModel) {
- debugPrint("text: \(model.text),index: \(model.index)")
- let msg = messageList.firstIndex (where: { (str,idx) in
- return idx == model.index;
- })
- if (msg == nil) {
- messageList.append((model.text,model.index))
- } else {
- messageList[msg!] = (model.text,model.index)
- }
-
- textView.text = messageList.compactMap({ (str,idx) in
- return str
- }).joined(separator: "\n")
- }
-
- func siManager(_ manager: JoyGemSIManager, didUpdateTranslate model: JoyGemAsrModel) {
- debugPrint("translate text: \(model.text),index: \(model.index)")
- let msg = translateList.firstIndex (where: { (str,idx) in
- return idx == model.index;
- })
- if (msg == nil) {
- translateList.append((model.text,model.index))
- } else {
- translateList[msg!] = (model.text,model.index)
- }
-
- translateTextView.text = translateList.compactMap({ (str,idx) in
- return str
- }).joined(separator: "\n")
- }
-
-
- func siManager(_ manager: JoyGemSIManager, saveFile path: String) {
- debugPrint("path: \(path)")
- recordFilePath = path
- }
-
- func siManager(_ manager: JoyGemSIManager, stateChange code: JoyGemStateCode) {
- debugPrint("code: \(code)")
- }
-
- func siManager(_ manager: JoyGemSIManager, didUpdateAudioData data: Data) {
- PcmSound.sharedInstance().feed(data)
- }
-
- func siManager(_ manager: JoyGemSIManager, onError code: JoyGemErrorCode) {
-
- }
-}
-
-extension SIViewController : PcmSoundDelegate {
-
- func remaining(_ frames: UInt) {
- debugPrint("[frame:\(frames)]");
- }
-}
+++ /dev/null
-//
-// SceneDelegate.swift
-// JoyGemAIDemo
-//
-// Created by JoyGem on 2025/2/10.
-//
-
-import UIKit
-
-class SceneDelegate: UIResponder, UIWindowSceneDelegate {
-
- var window: UIWindow?
-
-
- func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
- // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
- // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
- // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
- guard let _ = (scene as? UIWindowScene) else { return }
-
- }
-
- func sceneDidDisconnect(_ scene: UIScene) {
- // Called as the scene is being released by the system.
- // This occurs shortly after the scene enters the background, or when its session is discarded.
- // Release any resources associated with this scene that can be re-created the next time the scene connects.
- // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
- }
-
- func sceneDidBecomeActive(_ scene: UIScene) {
- // Called when the scene has moved from an inactive state to an active state.
- // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
- }
-
- func sceneWillResignActive(_ scene: UIScene) {
- // Called when the scene will move from an active state to an inactive state.
- // This may occur due to temporary interruptions (ex. an incoming phone call).
- }
-
- func sceneWillEnterForeground(_ scene: UIScene) {
- // Called as the scene transitions from the background to the foreground.
- // Use this method to undo the changes made on entering the background.
- }
-
- func sceneDidEnterBackground(_ scene: UIScene) {
- // Called as the scene transitions from the foreground to the background.
- // Use this method to save data, release shared resources, and store enough scene-specific state information
- // to restore the scene back to its current state.
- }
-
-
-}
-
+++ /dev/null
-//
-// RecordCall2ViewController.swift
-// JoyGemAIPod
-//
-// Created by jjjs on 2025/7/19.
-//
-
-import UIKit
-import SnapKit
-import JoyGemAI
-import AVFoundation
-import SVProgressHUD
-
-
-class StereoCallViewController: UIViewController {
-
- var selfTextView : UITextView!
-
- var otherTextView : UITextView!
-
- var startButton : UIButton!
-
- var stopButton : UIButton!
-
- var selfMessageList : [(String,UInt)] = []
-
- var otherMessageList : [(String,UInt)] = []
-
- var recordFilePath : String?
-
- override func viewDidLoad() {
- super.viewDidLoad()
- view.backgroundColor = UIColor.white
- title = "通话录音"
-
- self.navigationController?.navigationBar.tintColor = UIColor.black
- self.navigationItem.rightBarButtonItems = [
- UIBarButtonItem(title: "播放录音", style: .done, target: self, action: #selector(playRecord))
- ]
-
- selfTextView = UITextView()
- view.addSubview(selfTextView)
- selfTextView.snp.makeConstraints { make in
- make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
- make.leading.trailing.equalToSuperview()
- make.bottom.equalTo(view.snp.centerY).offset(-50)
- }
- selfTextView.backgroundColor = UIColor.gray
-
- otherTextView = UITextView()
- view.addSubview(otherTextView)
- otherTextView.snp.makeConstraints { make in
- make.top.equalTo(selfTextView.snp.bottom)
- make.leading.trailing.equalToSuperview()
- make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-100)
- }
- otherTextView.backgroundColor = UIColor.yellow
-
- startButton = UIButton(type: .custom)
- view.addSubview(startButton)
- startButton.snp.makeConstraints { make in
- make.top.equalTo(otherTextView.snp.bottom).offset(20)
- make.centerX.equalToSuperview().multipliedBy(0.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- startButton.setTitle("开始", for: .normal)
- startButton.setTitleColor(UIColor.darkText, for: .normal)
- startButton.addTarget(self, action: #selector(startRecord), for: .touchUpInside)
-
- stopButton = UIButton(type: .custom)
- view.addSubview(stopButton)
- stopButton.snp.makeConstraints { make in
- make.top.equalTo(otherTextView.snp.bottom).offset(20)
- make.centerX.equalToSuperview().multipliedBy(1.5)
- make.height.equalTo(60)
- make.width.equalTo(100)
- }
- stopButton.setTitle("结束", for: .normal)
- stopButton.setTitleColor(UIColor.darkText, for: .normal)
- stopButton.addTarget(self, action: #selector(endRecord), for: .touchUpInside)
-
- // Do any additional setup after loading the view.
- JoyGemCallManager.shared().delegate = self
- JoyGemCallManager.shared().stereoDelegate = self
- }
-
- @objc func startRecord() {
- selfMessageList.removeAll()
- otherMessageList.removeAll()
- selfTextView.text = nil
- otherTextView.text = nil
- JoyGemCallManager.shared().start()
- }
-
- @objc func endRecord() {
- JoyGemCallManager.shared().stop()
- }
-
- var audioPlayer: AVAudioPlayer?
-
- ///播放最后一次录音文件
- @objc func playRecord() {
- guard let file = recordFilePath else {return;}
-
- do {
- // 创建 AVAudioPlayer 实例
- audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: file))
- audioPlayer?.prepareToPlay() // 准备播放
- audioPlayer?.play() // 播放音频
- } catch {
- debugPrint("播放音频时发生错误: \(error.localizedDescription)")
- }
- }
-
-}
-
-extension StereoCallViewController : JoyGemCallManagerDelegate {
-
- func callManagerStopped(_ manager: JoyGemCallManager, reason code: JoyGemRecordStopCode) {
- if (code == .actively) {
- SVProgressHUD.showInfo(withStatus: "用户主动结束")
- } else {
- SVProgressHUD.showInfo(withStatus: "自动结束")
- ///判断当前蓝牙是否连接从而确定是否因为蓝牙断开造成的录音断开
- }
- }
-
- func callManagerNotonCall(_ manager: JoyGemCallManager) {
- SVProgressHUD.showInfo(withStatus: "未处于通话状态")
- }
-
- func callManager(_ manager: JoyGemCallManager, saveFile path: String) {
- debugPrint("path: \(path)")
- recordFilePath = path
- }
-
- func callManager(_ manager: JoyGemCallManager, stateChange code: JoyGemStateCode) {
- debugPrint("code: \(code)")
- }
-
- func callManager(_ manager: JoyGemCallManager, onError code: JoyGemErrorCode) {
-
- }
-
-}
-
-extension StereoCallViewController : JoyGemCallStereoDelegate {
-
- func callManager(_ manager: JoyGemCallManager, didUpdateStereoAsr model: JoyGemAsrModel, channel index: UInt) {
- debugPrint("text: \(model.text),index: \(model.index)")
- if (index == 1) {
- let msg = self.selfMessageList.firstIndex (where: { (str,idx) in
- return idx == model.index;
- })
- if (msg == nil) {
- selfMessageList.append((model.text,model.index))
- } else {
- selfMessageList[msg!] = (model.text,model.index)
- }
-
- selfTextView.text = selfMessageList.compactMap({ (str,idx) in
- return str
- }).joined(separator: "\n")
- } else if (index == 2) {
- let msg = otherMessageList.firstIndex (where: { (str,idx) in
- return idx == model.index;
- })
- if (msg == nil) {
- otherMessageList.append((model.text,model.index))
- } else {
- otherMessageList[msg!] = (model.text,model.index)
- }
-
- otherTextView.text = otherMessageList.compactMap({ (str,idx) in
- return str
- }).joined(separator: "\n")
- }
- }
-
-}
-
+++ /dev/null
-PODS:
- - SnapKit (5.7.1)
- - SocketRocket (0.7.1)
- - SVProgressHUD (2.3.1):
- - SVProgressHUD/Core (= 2.3.1)
- - SVProgressHUD/Core (2.3.1)
-
-DEPENDENCIES:
- - SnapKit (~> 5.7.0)
- - SocketRocket
- - SVProgressHUD
-
-SPEC REPOS:
- https://gitee.com/mirrors/CocoaPods-Specs.git:
- - SnapKit
- - SocketRocket
- - SVProgressHUD
-
-SPEC CHECKSUMS:
- SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a
- SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
- SVProgressHUD: 4837c74bdfe2e51e8821c397825996a8d7de6e22
-
-PODFILE CHECKSUM: 88e38ff2edfe5c4d422b709e72427b690a27bae3
-
-COCOAPODS: 1.16.1
+++ /dev/null
-PODS:
- - SnapKit (5.7.1)
- - SocketRocket (0.7.1)
- - SVProgressHUD (2.3.1):
- - SVProgressHUD/Core (= 2.3.1)
- - SVProgressHUD/Core (2.3.1)
-
-DEPENDENCIES:
- - SnapKit (~> 5.7.0)
- - SocketRocket
- - SVProgressHUD
-
-SPEC REPOS:
- https://gitee.com/mirrors/CocoaPods-Specs.git:
- - SnapKit
- - SocketRocket
- - SVProgressHUD
-
-SPEC CHECKSUMS:
- SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a
- SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
- SVProgressHUD: 4837c74bdfe2e51e8821c397825996a8d7de6e22
-
-PODFILE CHECKSUM: 88e38ff2edfe5c4d422b709e72427b690a27bae3
-
-COCOAPODS: 1.16.1
+++ /dev/null
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 71;
- objects = {
-
-/* Begin PBXBuildFile section */
- 0362BB03F32EC9FB6013DEE29E8E33EF /* SRHTTPConnectMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA0FDB8F2FF7D242A9C04D637F9395D /* SRHTTPConnectMessage.m */; };
- 04986EEC139DC7C45DAB58056315FDC8 /* SRPinningSecurityPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 078A1E3C0A17D73D5696661F2FD41355 /* SRPinningSecurityPolicy.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 064D909CD827405E8DCC309DB1B7775A /* ConstraintLayoutSupportDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1434BD4770B16AC5A1BA82148B7BFB4 /* ConstraintLayoutSupportDSL.swift */; };
- 07632D281C5DED61CC7866B079BC9D2C /* SocketRocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 40E1C989D96D36B27BDFC28C0DF32C37 /* SocketRocket.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 09E1F569A93FAD4B9149E30B9301F44A /* ConstraintPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC43E26F2BCEC3F8A82A37251E167C22 /* ConstraintPriority.swift */; };
- 0CA7A132ABE7018DE9295456732F38BB /* ConstraintAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C911B2CF87A65C277D3130EE4D4FE64F /* ConstraintAttributes.swift */; };
- 0DE5DB9C6227B3416778D8417DD95EA9 /* ConstraintView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EA184E57AC862564DDF1E17D31F0C15 /* ConstraintView+Extensions.swift */; };
- 1194E62AA3F6F506799B1A43B16942B5 /* ConstraintDirectionalInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = F50E99CEE87D7FAD33334B05B6F32808 /* ConstraintDirectionalInsets.swift */; };
- 14F6602F47FF59347CB6807CE217EDC5 /* SVProgressAnimatedView.h in Headers */ = {isa = PBXBuildFile; fileRef = BE1D7A8D31FE21DF99A4660B3D1AA623 /* SVProgressAnimatedView.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 1739C4B63D12177E58B7110F21E939EB /* SVIndefiniteAnimatedView.h in Headers */ = {isa = PBXBuildFile; fileRef = A93277EC2270FDDAA0958C56E051C8B0 /* SVIndefiniteAnimatedView.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 1A117EC847E321871E40EB39F3576D11 /* SRDelegateController.m in Sources */ = {isa = PBXBuildFile; fileRef = 185F6DDECC4865237EB7C1AE1B31056D /* SRDelegateController.m */; };
- 205EB01AED14BB574DD54EAFE26E4786 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71F2AFDF205411E56316964DE08D951E /* Foundation.framework */; };
- 20B8C7C05E3AF3032935F30500EF5550 /* SRIOConsumerPool.m in Sources */ = {isa = PBXBuildFile; fileRef = EC5BE341F8DFE6872E5F64B48F725FC2 /* SRIOConsumerPool.m */; };
- 2B2EB369550CE92CEEFCBFD3D32B8A3F /* ConstraintInsetTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E10254A0A8632CC477E958C7EC84BED /* ConstraintInsetTarget.swift */; };
- 2B7184BD487141C385B3CC3F3984AA55 /* SRSecurityPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 31A63CD82C66679A09F23A5F4C655209 /* SRSecurityPolicy.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 3577F172FA68CBAE47CFEE6FE25C5404 /* ConstraintOffsetTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB861D7993575C07991739F9E7CA580E /* ConstraintOffsetTarget.swift */; };
- 3BB0B5D924BE769E95E64A5E6FC1675D /* NSRunLoop+SRWebSocketPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C94F20D2970D27EE685FDD11155161C /* NSRunLoop+SRWebSocketPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 3D3B646B4988314275B40E97BEB16C7F /* ConstraintLayoutGuideDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 50BA59410948826A90BFE7A40CDD335E /* ConstraintLayoutGuideDSL.swift */; };
- 444E95921E2BDCE7512867EAA1A6B381 /* SRWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = B907B14F3A53FFA2D4AC8BE9952962B7 /* SRWebSocket.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 44EFA9A76932F81582D03076A8346A4B /* SRIOConsumerPool.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C37DBED4411BB9A4E32119E2C48E33A /* SRIOConsumerPool.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 4DC15DC2DF3C4BBA344C86B112C9C68B /* SRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 97D9FEC2E67EC3B9B83E4A19175262BC /* SRWebSocket.m */; };
- 4F4DEB687C0E4834A5B291DEE0651D6A /* ConstraintMaker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02380CEBB096C9215C757F7DD636E2F0 /* ConstraintMaker.swift */; };
- 517CF33F75EA768ED4B7F0F440F54A7E /* SVRadialGradientLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = EE1355ED3E31B0CBC6851479974B00A6 /* SVRadialGradientLayer.m */; };
- 56851E11140A140A15088A41DC4C33BD /* NSURLRequest+SRWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 577FF168360656D8723DCA6C8A4FFE94 /* NSURLRequest+SRWebSocket.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 57A34E19799F03EB53206496FD362449 /* SRURLUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 15F04AA9E58298DC3C28EEFD6F884C7B /* SRURLUtilities.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 57C4F6EFB30DDD14E960AC2D6B34F904 /* SnapKit-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = FC29B8849CE0100E7C6BE9C64A5AEB75 /* SnapKit-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 5922A6A0AE7152CF436356B3556F1835 /* ConstraintItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 325274FFB61CCB9521457A2368C080C8 /* ConstraintItem.swift */; };
- 59F34874DA4ABB2F5C4E09EA6865936B /* ConstraintLayoutGuide.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EF4B6714D4E828DFCB3F41D6E2BDE5A /* ConstraintLayoutGuide.swift */; };
- 5B67445AE2F3934BDA08D407BBA3028B /* SocketRocket-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = B9FD6FDF33FF7827E6C31546AB3EF28E /* SocketRocket-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 5DFD87881941225F0A5EAE64EB247708 /* SRSIMDHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = AEF784F41ECAE3C5470C7E86FEA09077 /* SRSIMDHelpers.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 5E7E257AE5D618E46EF57A5818010F85 /* NSRunLoop+SRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 919D3078BD5668ACA389A35AD945CFCB /* NSRunLoop+SRWebSocket.m */; };
- 6037BA6633BDFF4F63D6C8B7C70D6160 /* SVProgressHUD-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = D5BAD163B18A86FA28BB1B7FCDFDD532 /* SVProgressHUD-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 6135798CCD656C1B3A6EA5738A23190A /* SRSIMDHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 11C7808696C7AD7D8B09BA7956749A18 /* SRSIMDHelpers.m */; };
- 6464C345447C71904DA3706AACA3F55D /* SRProxyConnect.h in Headers */ = {isa = PBXBuildFile; fileRef = 20DCA1264B0FDE4CCC9B8EC324D8EC42 /* SRProxyConnect.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 65E5693A457A8AEE3E5758075D1E2792 /* SRError.h in Headers */ = {isa = PBXBuildFile; fileRef = 4E80B99F422C47FAE83A9416F6E4DDC5 /* SRError.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 6645E9FB4265C5712E38055C931E1630 /* NSURLRequest+SRWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E65DF20C67826C4F05933C9C548DE0 /* NSURLRequest+SRWebSocket.m */; };
- 6680C3C8924C7503A6A54CF7A66BFF2F /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 66549C441E7F0958A782198C074E2397 /* QuartzCore.framework */; };
- 6E39129FC8643A70C276801FEF4C280D /* Constraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA751B020F380C639CC250AD104C26D /* Constraint.swift */; };
- 7174D48AADABCBE6FC53185C5442B952 /* NSURLRequest+SRWebSocketPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = FDDAC95778CCFBCF273CB4E641A690E4 /* NSURLRequest+SRWebSocketPrivate.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 7804E0B3C98A2FE1E98AF544E88C9C3C /* SVRadialGradientLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7486DB51AD52B7D323095BFD71CE0EE9 /* SVRadialGradientLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 782981022BF319DFD85AE89A392639A2 /* SRMutex.h in Headers */ = {isa = PBXBuildFile; fileRef = B0DF85B6E4E98B26354EF0A3E5FEF528 /* SRMutex.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 7AF516B98D45391B909D507D0244104C /* ConstraintDescription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 592FF48826615BAAA38B97FE20C85BB1 /* ConstraintDescription.swift */; };
- 7B0DD32902633C7FF95B5745D8322BC3 /* SVProgressHUD.bundle in Resources */ = {isa = PBXBuildFile; fileRef = C982F402CB113B05D4B1F2A20FEE2040 /* SVProgressHUD.bundle */; };
- 7D42390CDB4FA147504B03DA2A174A0C /* ConstraintViewDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B0AF40C15008F0D0D92D22AE55A25CF /* ConstraintViewDSL.swift */; };
- 7F30D73D46CAD9D21A25738B11A6DDDA /* SRURLUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = A45A1FC09B35C7FBB139B6D0B5BA9737 /* SRURLUtilities.m */; };
- 868A9F524A7985BDA1EA124D9BF4CA63 /* ConstraintDSL.swift in Sources */ = {isa = PBXBuildFile; fileRef = D97B5B43639A927D54FB6F7B8CB5C5B0 /* ConstraintDSL.swift */; };
- 86CAB01D950C8BC35EDE0BDC01A2500B /* ConstraintView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 587F92D0AE85CB263F1149F5AAEE7C77 /* ConstraintView.swift */; };
- 883EDEE1C699497CF2A77C3B8A32A790 /* ConstraintMultiplierTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19C76CB8A25B2C660EA75AFF6647676C /* ConstraintMultiplierTarget.swift */; };
- 89717EC07E6324D3405867E754AE9131 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 23AD01048CEF57765D52B2EF4C55B397 /* PrivacyInfo.xcprivacy */; };
- 89CAC1E5DC5833EE630A652957D253A7 /* SRLog.h in Headers */ = {isa = PBXBuildFile; fileRef = BF42198EDA662CDDE17107F36890BE2F /* SRLog.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 8BABA32F7B94A25D8E9208C0A8D90B2E /* ConstraintMakerRelatable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14501D25D8F6E2B505819E760BA65A1C /* ConstraintMakerRelatable+Extensions.swift */; };
- 8D0D15CE4E92BA4433AE7EA578FE3E15 /* SRSecurityPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = C3650C85CE8A8BF1751F13A8A21CC5E4 /* SRSecurityPolicy.m */; };
- 8D58E2EE938A4E604B325A740C6FE7C7 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71F2AFDF205411E56316964DE08D951E /* Foundation.framework */; };
- 91930FDB4F9CCBBA9789806D1611AE6F /* SVProgressHUD.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CBDE8068311F3F149733424E931B569 /* SVProgressHUD.h */; settings = {ATTRIBUTES = (Public, ); }; };
- 92571FFBEF3A7B2F4F633624013010EE /* SRRunLoopThread.m in Sources */ = {isa = PBXBuildFile; fileRef = 64565DD0CD433588F260F50F66079582 /* SRRunLoopThread.m */; };
- 939EE0216FC02064B2F5894E87628182 /* SRRunLoopThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 85943BDD2DEECD3663D3A3BC6D684C1C /* SRRunLoopThread.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 9A3761D8CEFB0E2131D2EFA2DEBB3A99 /* SRRandom.m in Sources */ = {isa = PBXBuildFile; fileRef = 89D9E3C762868F41C4BBA43E1778A7A5 /* SRRandom.m */; };
- 9A3B9C740BC8FE0500132251551E5BE7 /* SRIOConsumer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4B7C748554BBA7785B4D717CD5C2FDB6 /* SRIOConsumer.h */; settings = {ATTRIBUTES = (Project, ); }; };
- 9E0045B41BFE697DB4ADE151228024D2 /* SnapKit_Privacy.bundle in Resources */ = {isa = PBXBuildFile; fileRef = B9DCB5EC0B1CDADD221717CADDF62359 /* SnapKit_Privacy.bundle */; };
- 9FD199868823028AAB5681E3B7BFFB0E /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 67B95EC9E4D9AE5D31C8B2940A90B732 /* PrivacyInfo.xcprivacy */; };
- A3585531EE4D8466B74A5A6F7958EC79 /* SocketRocket-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 90FCF59C1DB50D4CF155EDD7974926E4 /* SocketRocket-dummy.m */; };
- A564D0B0EE8AED950D943A75C2B3092E /* SRMutex.m in Sources */ = {isa = PBXBuildFile; fileRef = EA2411F3FE4D90B6D9BBABF80B5D9331 /* SRMutex.m */; };
- AABEF13464BA7F4621BD94736C1D057C /* ConstraintMakerPrioritizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A206653959B0FF746804314F156A55 /* ConstraintMakerPrioritizable.swift */; };
- AB12501C57FFF722131F674ACB425944 /* SRError.m in Sources */ = {isa = PBXBuildFile; fileRef = E7774F4ADD0B69233B7E17979DF8D668 /* SRError.m */; };
- ABC03808F32631C31667667948258ACE /* Pods-JoyGemAIDemo-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8A2D2C969321FF5F52A7272D95BCE8AC /* Pods-JoyGemAIDemo-dummy.m */; };
- AE224EDB6D044C0FE86B086E950FC2F9 /* Debugging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2E93F5EB563B0B1709714E647C1240BF /* Debugging.swift */; };
- AF760C78F1C7E11BF7CB9E9B29903530 /* ConstraintInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30DD110DC4E53BA27955E28A74EBD7A3 /* ConstraintInsets.swift */; };
- B0875E3AB8718E7DFE5C53497C02A15E /* ConstraintLayoutSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 874BE70592A52DF88EF06D6A66A9C38D /* ConstraintLayoutSupport.swift */; };
- B2A6C2397B8ADAE4D7D64B09FF82570E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71F2AFDF205411E56316964DE08D951E /* Foundation.framework */; };
- B4C82668A78939FE910FEA0D314F06C1 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 054C080A56516E4ADDA7E9FEEA2D4FD5 /* Security.framework */; };
- B543A1E1882CAEA19589891FCE2D17EA /* NSRunLoop+SRWebSocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 76BE51A7A16AD25A516A8FE62021D0E1 /* NSRunLoop+SRWebSocket.h */; settings = {ATTRIBUTES = (Public, ); }; };
- B893C0DD5BE32FAE1D6895E1ED392B7A /* SRConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 938BD9979B42CBFEC37273BC9C37A48C /* SRConstants.m */; };
- B903049E7C1BED7918DAB208754107C7 /* ConstraintMakerFinalizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D10B0EB05AA6B997D5B0C2BD95B7F0D1 /* ConstraintMakerFinalizable.swift */; };
- BA2FB695DEB0D179253EEB8DFCE3578B /* SnapKit-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = D78E01600A39734541D4990FC6683670 /* SnapKit-dummy.m */; };
- BDA5C7CC91E86448237CF40954FAC5AF /* ConstraintMakerRelatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08604283E18AF4DF7A4FD9107C1F37F3 /* ConstraintMakerRelatable.swift */; };
- BF1AE4D97E813B95C43EA4A298B973D1 /* LayoutConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 594672ACD25BFC6E05E3BEDC0AFF20B6 /* LayoutConstraint.swift */; };
- C07CB3E9A4D1BF00F841E4285629A2B2 /* ConstraintRelatableTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAC455D0F3897E6701EC5A5EC5169024 /* ConstraintRelatableTarget.swift */; };
- C14F10B663FE2898EACAB90C202B3F50 /* ConstraintMakerEditable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D44C0360646EEB24281F3D089EED5703 /* ConstraintMakerEditable.swift */; };
- C36214D8311B615CDA115276934926DC /* SRRandom.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CB86616CD8D64DBA9773C30C3AA41D6 /* SRRandom.h */; settings = {ATTRIBUTES = (Project, ); }; };
- C6A4302ACE006C4E2CDD481287E2916B /* Typealiases.swift in Sources */ = {isa = PBXBuildFile; fileRef = F431F8514500EB417A0B5D57D7C66A41 /* Typealiases.swift */; };
- C6F45595676957ADBEC18EB3F23EAEC4 /* LayoutConstraintItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C289513B354447D46903A2D85C93AC8 /* LayoutConstraintItem.swift */; };
- C92D93F48E74B79C08A2C5B81B68FD7D /* SRConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = CC5847BA2AD63E1B9FC7263CAB3E2498 /* SRConstants.h */; settings = {ATTRIBUTES = (Project, ); }; };
- CE593943A9E7CF83822CF60304BCAD43 /* ConstraintConstantTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B4292820E37A984166EB251147A0C53 /* ConstraintConstantTarget.swift */; };
- CEC96BA519484844D19338CC420C8808 /* SVIndefiniteAnimatedView.m in Sources */ = {isa = PBXBuildFile; fileRef = 24180F63622C3CEC513498B89CD16210 /* SVIndefiniteAnimatedView.m */; };
- CF6554D8A9380CAC0F51D5043769D930 /* SRLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BD1EE82BCA143564A9DEC60ADAC5504 /* SRLog.m */; };
- D25185C12789EA624C8BAC6A6432E77B /* SRPinningSecurityPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8381137A70938D1BBBB82AAFC63B0B1A /* SRPinningSecurityPolicy.m */; };
- D2E460754683003AE9ECF32A831D401F /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C94130B86B411D191585E6A223C3C694 /* CFNetwork.framework */; };
- D4218DA55B2BA45937589200CC0DF1FB /* ConstraintMakerExtendable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9EB218B2202FD67A414CBC2225522AC /* ConstraintMakerExtendable.swift */; };
- D623A6CB33709C4D87766C66A756A0F7 /* SRProxyConnect.m in Sources */ = {isa = PBXBuildFile; fileRef = 19947805A4B09C6EE4C89FC2C66ADD61 /* SRProxyConnect.m */; };
- DBA4803F4765E1650B8C6841157F5D73 /* ConstraintPriorityTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7DB8EF4BB696608C1219972EEA178A0 /* ConstraintPriorityTarget.swift */; };
- DEEC14319D7619F96C4E93415A6D577D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71F2AFDF205411E56316964DE08D951E /* Foundation.framework */; };
- DF011D18EBB28ECE459B6D96D3E460D8 /* SRHTTPConnectMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 572E05997DDC55370C47ED497255D8D3 /* SRHTTPConnectMessage.h */; settings = {ATTRIBUTES = (Project, ); }; };
- E30E824D8CE04C815FAD7F424CF7C270 /* SVProgressAnimatedView.m in Sources */ = {isa = PBXBuildFile; fileRef = E5F8233915D247512F6DA3B1B822E8F1 /* SVProgressAnimatedView.m */; };
- E37671A03B4C17A1CF3766A6125833BB /* ConstraintDirectionalInsetTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AFEE5E2D777166836C01E2C6AAD367 /* ConstraintDirectionalInsetTarget.swift */; };
- E3D779DEE753C0B0D33BA8E73A980265 /* ConstraintLayoutGuide+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EBE01132FEC7DFC40661AB6074C91B2 /* ConstraintLayoutGuide+Extensions.swift */; };
- EB3BCE9B36BF814DA3069FA077168301 /* SRHash.m in Sources */ = {isa = PBXBuildFile; fileRef = EE49421E2F86071271A52B1FDC1BDD58 /* SRHash.m */; };
- EC8DB2CC9791B7DC686DCC78EFBB56C5 /* SRDelegateController.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C6A15EB1F466050C1436D7E1E47EAB1 /* SRDelegateController.h */; settings = {ATTRIBUTES = (Project, ); }; };
- ECC5C2ADC2682F9171FEA22AF10DCE53 /* ConstraintRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1B3D76A156161A20CEC3824B6B09CC8 /* ConstraintRelation.swift */; };
- F6E948E2688CC08D3843DAA74F6328E8 /* SRHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C3A0C5D93DBB0A93DDFEEA897326433 /* SRHash.h */; settings = {ATTRIBUTES = (Project, ); }; };
- F6F33E8B268F3D41075374D95B8088DC /* UILayoutSupport+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D360D2580F6F41C8ABE2606EB7A25C77 /* UILayoutSupport+Extensions.swift */; };
- F87D4D6C6668A4AA86232BA3BDB9A178 /* SVProgressHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = F88289484721B3C5C1115A55CB12EBB0 /* SVProgressHUD.m */; };
- F9EBA65892D78A31C068D727D84BCB88 /* ConstraintConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5F0D1785B06919A2E028A38C5AF699 /* ConstraintConfig.swift */; };
- FB75853E6A0E0682E1000CFBD293EBBC /* SVProgressHUD-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = B03C9AC7EA6EBD11AA5CC20269FAF955 /* SVProgressHUD-dummy.m */; };
- FBEDAA38D7E0B3C8DEE459EAA095C48C /* Pods-JoyGemAIDemo-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EE9B930126DDD3F7D558DDA0EC8A710 /* Pods-JoyGemAIDemo-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
- FCFC8D5B48F3DC4BC8942320631D8C1B /* SRIOConsumer.m in Sources */ = {isa = PBXBuildFile; fileRef = 5560650533F07B36E06B6F96E4FFF307 /* SRIOConsumer.m */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXContainerItemProxy section */
- 835DF671A580FED0D976A9BE52562532 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 1948D0B63D2CF6A48E18B0B292BC6091;
- remoteInfo = SocketRocket;
- };
- A2037CAFBFB3B718C2AE2F4FB05B8705 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 1C8D67D8B72D6BA42CCEDB648537A340;
- remoteInfo = SVProgressHUD;
- };
- C860B402EF6D807222EE55F2EA175448 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 8A8DB685241263AFDF5E6B20FE67B93A;
- remoteInfo = "SnapKit-SnapKit_Privacy";
- };
- FD48D631BAD9713237222F94224B4230 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 19622742EBA51E823D6DAE3F8CDBFAD4;
- remoteInfo = SnapKit;
- };
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXFileReference section */
- 02380CEBB096C9215C757F7DD636E2F0 /* ConstraintMaker.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintMaker.swift; path = Sources/ConstraintMaker.swift; sourceTree = "<group>"; };
- 030FEB9982732056707F3135743826F1 /* Pods-JoyGemAIDemo-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-JoyGemAIDemo-frameworks.sh"; sourceTree = "<group>"; };
- 054C080A56516E4ADDA7E9FEEA2D4FD5 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
- 078A1E3C0A17D73D5696661F2FD41355 /* SRPinningSecurityPolicy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRPinningSecurityPolicy.h; path = SocketRocket/Internal/Security/SRPinningSecurityPolicy.h; sourceTree = "<group>"; };
- 08604283E18AF4DF7A4FD9107C1F37F3 /* ConstraintMakerRelatable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintMakerRelatable.swift; path = Sources/ConstraintMakerRelatable.swift; sourceTree = "<group>"; };
- 0B0AF40C15008F0D0D92D22AE55A25CF /* ConstraintViewDSL.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintViewDSL.swift; path = Sources/ConstraintViewDSL.swift; sourceTree = "<group>"; };
- 11C7808696C7AD7D8B09BA7956749A18 /* SRSIMDHelpers.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRSIMDHelpers.m; path = SocketRocket/Internal/Utilities/SRSIMDHelpers.m; sourceTree = "<group>"; };
- 12B256489F57DB0D7209DFE5DDC0D705 /* Pods-JoyGemAIDemo.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-JoyGemAIDemo.modulemap"; sourceTree = "<group>"; };
- 14501D25D8F6E2B505819E760BA65A1C /* ConstraintMakerRelatable+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ConstraintMakerRelatable+Extensions.swift"; path = "Sources/ConstraintMakerRelatable+Extensions.swift"; sourceTree = "<group>"; };
- 15F04AA9E58298DC3C28EEFD6F884C7B /* SRURLUtilities.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRURLUtilities.h; path = SocketRocket/Internal/Utilities/SRURLUtilities.h; sourceTree = "<group>"; };
- 185F6DDECC4865237EB7C1AE1B31056D /* SRDelegateController.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRDelegateController.m; path = SocketRocket/Internal/Delegate/SRDelegateController.m; sourceTree = "<group>"; };
- 19947805A4B09C6EE4C89FC2C66ADD61 /* SRProxyConnect.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRProxyConnect.m; path = SocketRocket/Internal/Proxy/SRProxyConnect.m; sourceTree = "<group>"; };
- 19C76CB8A25B2C660EA75AFF6647676C /* ConstraintMultiplierTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintMultiplierTarget.swift; path = Sources/ConstraintMultiplierTarget.swift; sourceTree = "<group>"; };
- 1BD1EE82BCA143564A9DEC60ADAC5504 /* SRLog.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRLog.m; path = SocketRocket/Internal/Utilities/SRLog.m; sourceTree = "<group>"; };
- 20DCA1264B0FDE4CCC9B8EC324D8EC42 /* SRProxyConnect.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRProxyConnect.h; path = SocketRocket/Internal/Proxy/SRProxyConnect.h; sourceTree = "<group>"; };
- 23AD01048CEF57765D52B2EF4C55B397 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = SVProgressHUD/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
- 24180F63622C3CEC513498B89CD16210 /* SVIndefiniteAnimatedView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SVIndefiniteAnimatedView.m; path = SVProgressHUD/SVIndefiniteAnimatedView.m; sourceTree = "<group>"; };
- 2763F459D69C3B6B4108DE8ABA731567 /* SVProgressHUD.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = SVProgressHUD.modulemap; sourceTree = "<group>"; };
- 2E93F5EB563B0B1709714E647C1240BF /* Debugging.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Debugging.swift; path = Sources/Debugging.swift; sourceTree = "<group>"; };
- 30DD110DC4E53BA27955E28A74EBD7A3 /* ConstraintInsets.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintInsets.swift; path = Sources/ConstraintInsets.swift; sourceTree = "<group>"; };
- 31A63CD82C66679A09F23A5F4C655209 /* SRSecurityPolicy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRSecurityPolicy.h; path = SocketRocket/SRSecurityPolicy.h; sourceTree = "<group>"; };
- 325274FFB61CCB9521457A2368C080C8 /* ConstraintItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintItem.swift; path = Sources/ConstraintItem.swift; sourceTree = "<group>"; };
- 34A206653959B0FF746804314F156A55 /* ConstraintMakerPrioritizable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintMakerPrioritizable.swift; path = Sources/ConstraintMakerPrioritizable.swift; sourceTree = "<group>"; };
- 38551E64867CE5BAFB66EC57CC2863F7 /* Pods-JoyGemAIDemo-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-JoyGemAIDemo-Info.plist"; sourceTree = "<group>"; };
- 38A9A085D1DF5C3194ADEDC57264C009 /* SocketRocket-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SocketRocket-prefix.pch"; sourceTree = "<group>"; };
- 3B4292820E37A984166EB251147A0C53 /* ConstraintConstantTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintConstantTarget.swift; path = Sources/ConstraintConstantTarget.swift; sourceTree = "<group>"; };
- 3EF4B6714D4E828DFCB3F41D6E2BDE5A /* ConstraintLayoutGuide.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintLayoutGuide.swift; path = Sources/ConstraintLayoutGuide.swift; sourceTree = "<group>"; };
- 40E1C989D96D36B27BDFC28C0DF32C37 /* SocketRocket.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SocketRocket.h; path = SocketRocket/SocketRocket.h; sourceTree = "<group>"; };
- 4B7C748554BBA7785B4D717CD5C2FDB6 /* SRIOConsumer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRIOConsumer.h; path = SocketRocket/Internal/IOConsumer/SRIOConsumer.h; sourceTree = "<group>"; };
- 4C3A0C5D93DBB0A93DDFEEA897326433 /* SRHash.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRHash.h; path = SocketRocket/Internal/Utilities/SRHash.h; sourceTree = "<group>"; };
- 4C94F20D2970D27EE685FDD11155161C /* NSRunLoop+SRWebSocketPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSRunLoop+SRWebSocketPrivate.h"; path = "SocketRocket/Internal/NSRunLoop+SRWebSocketPrivate.h"; sourceTree = "<group>"; };
- 4CB86616CD8D64DBA9773C30C3AA41D6 /* SRRandom.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRRandom.h; path = SocketRocket/Internal/Utilities/SRRandom.h; sourceTree = "<group>"; };
- 4E80B99F422C47FAE83A9416F6E4DDC5 /* SRError.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRError.h; path = SocketRocket/Internal/Utilities/SRError.h; sourceTree = "<group>"; };
- 4EA184E57AC862564DDF1E17D31F0C15 /* ConstraintView+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ConstraintView+Extensions.swift"; path = "Sources/ConstraintView+Extensions.swift"; sourceTree = "<group>"; };
- 4EE9B930126DDD3F7D558DDA0EC8A710 /* Pods-JoyGemAIDemo-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-JoyGemAIDemo-umbrella.h"; sourceTree = "<group>"; };
- 50BA59410948826A90BFE7A40CDD335E /* ConstraintLayoutGuideDSL.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintLayoutGuideDSL.swift; path = Sources/ConstraintLayoutGuideDSL.swift; sourceTree = "<group>"; };
- 5560650533F07B36E06B6F96E4FFF307 /* SRIOConsumer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRIOConsumer.m; path = SocketRocket/Internal/IOConsumer/SRIOConsumer.m; sourceTree = "<group>"; };
- 55E5E095252D79C57304FFB017BB0BC5 /* SVProgressHUD-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SVProgressHUD-Info.plist"; sourceTree = "<group>"; };
- 572E05997DDC55370C47ED497255D8D3 /* SRHTTPConnectMessage.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRHTTPConnectMessage.h; path = SocketRocket/Internal/Utilities/SRHTTPConnectMessage.h; sourceTree = "<group>"; };
- 577FF168360656D8723DCA6C8A4FFE94 /* NSURLRequest+SRWebSocket.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSURLRequest+SRWebSocket.h"; path = "SocketRocket/NSURLRequest+SRWebSocket.h"; sourceTree = "<group>"; };
- 587F92D0AE85CB263F1149F5AAEE7C77 /* ConstraintView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintView.swift; path = Sources/ConstraintView.swift; sourceTree = "<group>"; };
- 592FF48826615BAAA38B97FE20C85BB1 /* ConstraintDescription.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintDescription.swift; path = Sources/ConstraintDescription.swift; sourceTree = "<group>"; };
- 594672ACD25BFC6E05E3BEDC0AFF20B6 /* LayoutConstraint.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LayoutConstraint.swift; path = Sources/LayoutConstraint.swift; sourceTree = "<group>"; };
- 5C37DBED4411BB9A4E32119E2C48E33A /* SRIOConsumerPool.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRIOConsumerPool.h; path = SocketRocket/Internal/IOConsumer/SRIOConsumerPool.h; sourceTree = "<group>"; };
- 62A9979254233B73B95007D708D1E25A /* SnapKit-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SnapKit-prefix.pch"; sourceTree = "<group>"; };
- 63E65DF20C67826C4F05933C9C548DE0 /* NSURLRequest+SRWebSocket.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSURLRequest+SRWebSocket.m"; path = "SocketRocket/NSURLRequest+SRWebSocket.m"; sourceTree = "<group>"; };
- 64565DD0CD433588F260F50F66079582 /* SRRunLoopThread.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRRunLoopThread.m; path = SocketRocket/Internal/RunLoop/SRRunLoopThread.m; sourceTree = "<group>"; };
- 66549C441E7F0958A782198C074E2397 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk/System/Library/Frameworks/QuartzCore.framework; sourceTree = DEVELOPER_DIR; };
- 67B95EC9E4D9AE5D31C8B2940A90B732 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xml; name = PrivacyInfo.xcprivacy; path = Sources/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
- 6BA0FDB8F2FF7D242A9C04D637F9395D /* SRHTTPConnectMessage.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRHTTPConnectMessage.m; path = SocketRocket/Internal/Utilities/SRHTTPConnectMessage.m; sourceTree = "<group>"; };
- 6C6A15EB1F466050C1436D7E1E47EAB1 /* SRDelegateController.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRDelegateController.h; path = SocketRocket/Internal/Delegate/SRDelegateController.h; sourceTree = "<group>"; };
- 71F2AFDF205411E56316964DE08D951E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
- 7486DB51AD52B7D323095BFD71CE0EE9 /* SVRadialGradientLayer.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SVRadialGradientLayer.h; path = SVProgressHUD/SVRadialGradientLayer.h; sourceTree = "<group>"; };
- 76BE51A7A16AD25A516A8FE62021D0E1 /* NSRunLoop+SRWebSocket.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSRunLoop+SRWebSocket.h"; path = "SocketRocket/NSRunLoop+SRWebSocket.h"; sourceTree = "<group>"; };
- 7BA73F09977C922C7B7FA7C0B234E9E3 /* SnapKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SnapKit.release.xcconfig; sourceTree = "<group>"; };
- 8381137A70938D1BBBB82AAFC63B0B1A /* SRPinningSecurityPolicy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRPinningSecurityPolicy.m; path = SocketRocket/Internal/Security/SRPinningSecurityPolicy.m; sourceTree = "<group>"; };
- 85943BDD2DEECD3663D3A3BC6D684C1C /* SRRunLoopThread.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRRunLoopThread.h; path = SocketRocket/Internal/RunLoop/SRRunLoopThread.h; sourceTree = "<group>"; };
- 85A01882ED06DFEA2E0CE78BCDB204A7 /* SocketRocket.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SocketRocket.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 874BE70592A52DF88EF06D6A66A9C38D /* ConstraintLayoutSupport.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintLayoutSupport.swift; path = Sources/ConstraintLayoutSupport.swift; sourceTree = "<group>"; };
- 89D9E3C762868F41C4BBA43E1778A7A5 /* SRRandom.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRRandom.m; path = SocketRocket/Internal/Utilities/SRRandom.m; sourceTree = "<group>"; };
- 8A2D2C969321FF5F52A7272D95BCE8AC /* Pods-JoyGemAIDemo-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-JoyGemAIDemo-dummy.m"; sourceTree = "<group>"; };
- 8C289513B354447D46903A2D85C93AC8 /* LayoutConstraintItem.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LayoutConstraintItem.swift; path = Sources/LayoutConstraintItem.swift; sourceTree = "<group>"; };
- 8CBDE8068311F3F149733424E931B569 /* SVProgressHUD.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SVProgressHUD.h; path = SVProgressHUD/SVProgressHUD.h; sourceTree = "<group>"; };
- 8D52542CF6C393E7708BED48E72DD679 /* Pods-JoyGemAIDemo-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-JoyGemAIDemo-acknowledgements.plist"; sourceTree = "<group>"; };
- 8F23DB1C587B4583CD55800A55481EB6 /* SocketRocket.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SocketRocket.release.xcconfig; sourceTree = "<group>"; };
- 90FCF59C1DB50D4CF155EDD7974926E4 /* SocketRocket-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SocketRocket-dummy.m"; sourceTree = "<group>"; };
- 919D3078BD5668ACA389A35AD945CFCB /* NSRunLoop+SRWebSocket.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = "NSRunLoop+SRWebSocket.m"; path = "SocketRocket/NSRunLoop+SRWebSocket.m"; sourceTree = "<group>"; };
- 925714E4666F0554718E983964951A8B /* SVProgressHUD.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SVProgressHUD.debug.xcconfig; sourceTree = "<group>"; };
- 93096358FB9D70A7A7498BAA812CCA52 /* Pods-JoyGemAIDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-JoyGemAIDemo.release.xcconfig"; sourceTree = "<group>"; };
- 938BD9979B42CBFEC37273BC9C37A48C /* SRConstants.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRConstants.m; path = SocketRocket/Internal/SRConstants.m; sourceTree = "<group>"; };
- 979486118B3E90C08386079D57962701 /* SnapKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SnapKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 97D9FEC2E67EC3B9B83E4A19175262BC /* SRWebSocket.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRWebSocket.m; path = SocketRocket/SRWebSocket.m; sourceTree = "<group>"; };
- 9A9313FF4398CEE1734CB6357724A7F1 /* Pods-JoyGemAIDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-JoyGemAIDemo.debug.xcconfig"; sourceTree = "<group>"; };
- 9B46A4A44CEAE7F06EDD05B954176D2C /* SVProgressHUD-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SVProgressHUD-prefix.pch"; sourceTree = "<group>"; };
- 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
- 9E10254A0A8632CC477E958C7EC84BED /* ConstraintInsetTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintInsetTarget.swift; path = Sources/ConstraintInsetTarget.swift; sourceTree = "<group>"; };
- 9EBE01132FEC7DFC40661AB6074C91B2 /* ConstraintLayoutGuide+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "ConstraintLayoutGuide+Extensions.swift"; path = "Sources/ConstraintLayoutGuide+Extensions.swift"; sourceTree = "<group>"; };
- A45A1FC09B35C7FBB139B6D0B5BA9737 /* SRURLUtilities.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRURLUtilities.m; path = SocketRocket/Internal/Utilities/SRURLUtilities.m; sourceTree = "<group>"; };
- A93277EC2270FDDAA0958C56E051C8B0 /* SVIndefiniteAnimatedView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SVIndefiniteAnimatedView.h; path = SVProgressHUD/SVIndefiniteAnimatedView.h; sourceTree = "<group>"; };
- AB861D7993575C07991739F9E7CA580E /* ConstraintOffsetTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintOffsetTarget.swift; path = Sources/ConstraintOffsetTarget.swift; sourceTree = "<group>"; };
- AC43E26F2BCEC3F8A82A37251E167C22 /* ConstraintPriority.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintPriority.swift; path = Sources/ConstraintPriority.swift; sourceTree = "<group>"; };
- AEF784F41ECAE3C5470C7E86FEA09077 /* SRSIMDHelpers.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRSIMDHelpers.h; path = SocketRocket/Internal/Utilities/SRSIMDHelpers.h; sourceTree = "<group>"; };
- B03C9AC7EA6EBD11AA5CC20269FAF955 /* SVProgressHUD-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SVProgressHUD-dummy.m"; sourceTree = "<group>"; };
- B0DF85B6E4E98B26354EF0A3E5FEF528 /* SRMutex.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRMutex.h; path = SocketRocket/Internal/Utilities/SRMutex.h; sourceTree = "<group>"; };
- B2B52318F57059FC39EB5115B64E4FCF /* SVProgressHUD.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SVProgressHUD.release.xcconfig; sourceTree = "<group>"; };
- B907B14F3A53FFA2D4AC8BE9952962B7 /* SRWebSocket.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRWebSocket.h; path = SocketRocket/SRWebSocket.h; sourceTree = "<group>"; };
- B9DCB5EC0B1CDADD221717CADDF62359 /* SnapKit_Privacy.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SnapKit_Privacy.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
- B9FD6FDF33FF7827E6C31546AB3EF28E /* SocketRocket-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SocketRocket-umbrella.h"; sourceTree = "<group>"; };
- BAC455D0F3897E6701EC5A5EC5169024 /* ConstraintRelatableTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintRelatableTarget.swift; path = Sources/ConstraintRelatableTarget.swift; sourceTree = "<group>"; };
- BE1D7A8D31FE21DF99A4660B3D1AA623 /* SVProgressAnimatedView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SVProgressAnimatedView.h; path = SVProgressHUD/SVProgressAnimatedView.h; sourceTree = "<group>"; };
- BF42198EDA662CDDE17107F36890BE2F /* SRLog.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRLog.h; path = SocketRocket/Internal/Utilities/SRLog.h; sourceTree = "<group>"; };
- C3650C85CE8A8BF1751F13A8A21CC5E4 /* SRSecurityPolicy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRSecurityPolicy.m; path = SocketRocket/SRSecurityPolicy.m; sourceTree = "<group>"; };
- C911B2CF87A65C277D3130EE4D4FE64F /* ConstraintAttributes.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintAttributes.swift; path = Sources/ConstraintAttributes.swift; sourceTree = "<group>"; };
- C94130B86B411D191585E6A223C3C694 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS18.0.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; };
- C982F402CB113B05D4B1F2A20FEE2040 /* SVProgressHUD.bundle */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = "wrapper.plug-in"; name = SVProgressHUD.bundle; path = SVProgressHUD/SVProgressHUD.bundle; sourceTree = "<group>"; };
- CC293BBB9A5E4968EE4ED5F611BF8162 /* SocketRocket.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SocketRocket.debug.xcconfig; sourceTree = "<group>"; };
- CC5847BA2AD63E1B9FC7263CAB3E2498 /* SRConstants.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = SRConstants.h; path = SocketRocket/Internal/SRConstants.h; sourceTree = "<group>"; };
- CDBBCEA019AFD586193D94A34E344E7A /* Pods-JoyGemAIDemo-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-JoyGemAIDemo-acknowledgements.markdown"; sourceTree = "<group>"; };
- D10B0EB05AA6B997D5B0C2BD95B7F0D1 /* ConstraintMakerFinalizable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintMakerFinalizable.swift; path = Sources/ConstraintMakerFinalizable.swift; sourceTree = "<group>"; };
- D137CAEEE2D408A7495FA50188CB4D52 /* SnapKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = SnapKit.debug.xcconfig; sourceTree = "<group>"; };
- D1B3D76A156161A20CEC3824B6B09CC8 /* ConstraintRelation.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintRelation.swift; path = Sources/ConstraintRelation.swift; sourceTree = "<group>"; };
- D360D2580F6F41C8ABE2606EB7A25C77 /* UILayoutSupport+Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UILayoutSupport+Extensions.swift"; path = "Sources/UILayoutSupport+Extensions.swift"; sourceTree = "<group>"; };
- D44C0360646EEB24281F3D089EED5703 /* ConstraintMakerEditable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintMakerEditable.swift; path = Sources/ConstraintMakerEditable.swift; sourceTree = "<group>"; };
- D5AFEE5E2D777166836C01E2C6AAD367 /* ConstraintDirectionalInsetTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintDirectionalInsetTarget.swift; path = Sources/ConstraintDirectionalInsetTarget.swift; sourceTree = "<group>"; };
- D5BAD163B18A86FA28BB1B7FCDFDD532 /* SVProgressHUD-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SVProgressHUD-umbrella.h"; sourceTree = "<group>"; };
- D78E01600A39734541D4990FC6683670 /* SnapKit-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "SnapKit-dummy.m"; sourceTree = "<group>"; };
- D863F9DE61CFC7AA3F031CE3260FFE4D /* Pods_JoyGemAIDemo.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JoyGemAIDemo.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- D97B5B43639A927D54FB6F7B8CB5C5B0 /* ConstraintDSL.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintDSL.swift; path = Sources/ConstraintDSL.swift; sourceTree = "<group>"; };
- D9EB218B2202FD67A414CBC2225522AC /* ConstraintMakerExtendable.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintMakerExtendable.swift; path = Sources/ConstraintMakerExtendable.swift; sourceTree = "<group>"; };
- DB5F0D1785B06919A2E028A38C5AF699 /* ConstraintConfig.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintConfig.swift; path = Sources/ConstraintConfig.swift; sourceTree = "<group>"; };
- E1434BD4770B16AC5A1BA82148B7BFB4 /* ConstraintLayoutSupportDSL.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintLayoutSupportDSL.swift; path = Sources/ConstraintLayoutSupportDSL.swift; sourceTree = "<group>"; };
- E5F8233915D247512F6DA3B1B822E8F1 /* SVProgressAnimatedView.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SVProgressAnimatedView.m; path = SVProgressHUD/SVProgressAnimatedView.m; sourceTree = "<group>"; };
- E7774F4ADD0B69233B7E17979DF8D668 /* SRError.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRError.m; path = SocketRocket/Internal/Utilities/SRError.m; sourceTree = "<group>"; };
- E7DB8EF4BB696608C1219972EEA178A0 /* ConstraintPriorityTarget.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintPriorityTarget.swift; path = Sources/ConstraintPriorityTarget.swift; sourceTree = "<group>"; };
- E97D43C46A45EE515A4DA3AF94398441 /* SVProgressHUD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SVProgressHUD.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- EA2411F3FE4D90B6D9BBABF80B5D9331 /* SRMutex.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRMutex.m; path = SocketRocket/Internal/Utilities/SRMutex.m; sourceTree = "<group>"; };
- EC5BE341F8DFE6872E5F64B48F725FC2 /* SRIOConsumerPool.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRIOConsumerPool.m; path = SocketRocket/Internal/IOConsumer/SRIOConsumerPool.m; sourceTree = "<group>"; };
- ECDC2C14E25B69CE4704D7F90C1E36A0 /* SnapKit-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SnapKit-Info.plist"; sourceTree = "<group>"; };
- EE1355ED3E31B0CBC6851479974B00A6 /* SVRadialGradientLayer.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SVRadialGradientLayer.m; path = SVProgressHUD/SVRadialGradientLayer.m; sourceTree = "<group>"; };
- EE49421E2F86071271A52B1FDC1BDD58 /* SRHash.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SRHash.m; path = SocketRocket/Internal/Utilities/SRHash.m; sourceTree = "<group>"; };
- F431F8514500EB417A0B5D57D7C66A41 /* Typealiases.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Typealiases.swift; path = Sources/Typealiases.swift; sourceTree = "<group>"; };
- F50E99CEE87D7FAD33334B05B6F32808 /* ConstraintDirectionalInsets.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ConstraintDirectionalInsets.swift; path = Sources/ConstraintDirectionalInsets.swift; sourceTree = "<group>"; };
- F528C8C0205117E6E6107CE8AFF03E77 /* ResourceBundle-SnapKit_Privacy-SnapKit-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "ResourceBundle-SnapKit_Privacy-SnapKit-Info.plist"; sourceTree = "<group>"; };
- F88289484721B3C5C1115A55CB12EBB0 /* SVProgressHUD.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = SVProgressHUD.m; path = SVProgressHUD/SVProgressHUD.m; sourceTree = "<group>"; };
- F98682923B0BCA998E6618158F2101FB /* SocketRocket.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = SocketRocket.modulemap; sourceTree = "<group>"; };
- FC29B8849CE0100E7C6BE9C64A5AEB75 /* SnapKit-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "SnapKit-umbrella.h"; sourceTree = "<group>"; };
- FCE1C0E0C79D2C33462819FC7CA8AF38 /* SnapKit.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = SnapKit.modulemap; sourceTree = "<group>"; };
- FDDAC95778CCFBCF273CB4E641A690E4 /* NSURLRequest+SRWebSocketPrivate.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "NSURLRequest+SRWebSocketPrivate.h"; path = "SocketRocket/Internal/NSURLRequest+SRWebSocketPrivate.h"; sourceTree = "<group>"; };
- FE21277BF9017D281A07A338D5F51D92 /* SocketRocket-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "SocketRocket-Info.plist"; sourceTree = "<group>"; };
- FFA751B020F380C639CC250AD104C26D /* Constraint.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Constraint.swift; path = Sources/Constraint.swift; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 33428AC36668E3ED52DB70316F843FB8 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 205EB01AED14BB574DD54EAFE26E4786 /* Foundation.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 4B4CD810BB6E6D719ECFED6C6CA9C997 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 58634B2196876B07B5310C7EACCF921E /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- B2A6C2397B8ADAE4D7D64B09FF82570E /* Foundation.framework in Frameworks */,
- 6680C3C8924C7503A6A54CF7A66BFF2F /* QuartzCore.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 796567F81D938DA74DF71A2AFF3F8F3D /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D2E460754683003AE9ECF32A831D401F /* CFNetwork.framework in Frameworks */,
- DEEC14319D7619F96C4E93415A6D577D /* Foundation.framework in Frameworks */,
- B4C82668A78939FE910FEA0D314F06C1 /* Security.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 8CBA52A0E5D17C5026C3C675B65FA403 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 8D58E2EE938A4E604B325A740C6FE7C7 /* Foundation.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 00234441CF7C8CCEE3F7647B94F6BDAC /* Core */ = {
- isa = PBXGroup;
- children = (
- A93277EC2270FDDAA0958C56E051C8B0 /* SVIndefiniteAnimatedView.h */,
- 24180F63622C3CEC513498B89CD16210 /* SVIndefiniteAnimatedView.m */,
- BE1D7A8D31FE21DF99A4660B3D1AA623 /* SVProgressAnimatedView.h */,
- E5F8233915D247512F6DA3B1B822E8F1 /* SVProgressAnimatedView.m */,
- 8CBDE8068311F3F149733424E931B569 /* SVProgressHUD.h */,
- F88289484721B3C5C1115A55CB12EBB0 /* SVProgressHUD.m */,
- 7486DB51AD52B7D323095BFD71CE0EE9 /* SVRadialGradientLayer.h */,
- EE1355ED3E31B0CBC6851479974B00A6 /* SVRadialGradientLayer.m */,
- EBDCD60CA22CA04B2A7F8036D19F82BF /* Resources */,
- );
- name = Core;
- sourceTree = "<group>";
- };
- 0165B987DA4D81EB7DFC7EAEBFAABFBB /* Support Files */ = {
- isa = PBXGroup;
- children = (
- F528C8C0205117E6E6107CE8AFF03E77 /* ResourceBundle-SnapKit_Privacy-SnapKit-Info.plist */,
- FCE1C0E0C79D2C33462819FC7CA8AF38 /* SnapKit.modulemap */,
- D78E01600A39734541D4990FC6683670 /* SnapKit-dummy.m */,
- ECDC2C14E25B69CE4704D7F90C1E36A0 /* SnapKit-Info.plist */,
- 62A9979254233B73B95007D708D1E25A /* SnapKit-prefix.pch */,
- FC29B8849CE0100E7C6BE9C64A5AEB75 /* SnapKit-umbrella.h */,
- D137CAEEE2D408A7495FA50188CB4D52 /* SnapKit.debug.xcconfig */,
- 7BA73F09977C922C7B7FA7C0B234E9E3 /* SnapKit.release.xcconfig */,
- );
- name = "Support Files";
- path = "../Target Support Files/SnapKit";
- sourceTree = "<group>";
- };
- 05509D3D469F558F8658F676D8E4BCA2 /* Resources */ = {
- isa = PBXGroup;
- children = (
- 67B95EC9E4D9AE5D31C8B2940A90B732 /* PrivacyInfo.xcprivacy */,
- );
- name = Resources;
- sourceTree = "<group>";
- };
- 11A5B8FCBF685FD503D053A5E1B57B5A /* SnapKit */ = {
- isa = PBXGroup;
- children = (
- FFA751B020F380C639CC250AD104C26D /* Constraint.swift */,
- C911B2CF87A65C277D3130EE4D4FE64F /* ConstraintAttributes.swift */,
- DB5F0D1785B06919A2E028A38C5AF699 /* ConstraintConfig.swift */,
- 3B4292820E37A984166EB251147A0C53 /* ConstraintConstantTarget.swift */,
- 592FF48826615BAAA38B97FE20C85BB1 /* ConstraintDescription.swift */,
- F50E99CEE87D7FAD33334B05B6F32808 /* ConstraintDirectionalInsets.swift */,
- D5AFEE5E2D777166836C01E2C6AAD367 /* ConstraintDirectionalInsetTarget.swift */,
- D97B5B43639A927D54FB6F7B8CB5C5B0 /* ConstraintDSL.swift */,
- 30DD110DC4E53BA27955E28A74EBD7A3 /* ConstraintInsets.swift */,
- 9E10254A0A8632CC477E958C7EC84BED /* ConstraintInsetTarget.swift */,
- 325274FFB61CCB9521457A2368C080C8 /* ConstraintItem.swift */,
- 3EF4B6714D4E828DFCB3F41D6E2BDE5A /* ConstraintLayoutGuide.swift */,
- 9EBE01132FEC7DFC40661AB6074C91B2 /* ConstraintLayoutGuide+Extensions.swift */,
- 50BA59410948826A90BFE7A40CDD335E /* ConstraintLayoutGuideDSL.swift */,
- 874BE70592A52DF88EF06D6A66A9C38D /* ConstraintLayoutSupport.swift */,
- E1434BD4770B16AC5A1BA82148B7BFB4 /* ConstraintLayoutSupportDSL.swift */,
- 02380CEBB096C9215C757F7DD636E2F0 /* ConstraintMaker.swift */,
- D44C0360646EEB24281F3D089EED5703 /* ConstraintMakerEditable.swift */,
- D9EB218B2202FD67A414CBC2225522AC /* ConstraintMakerExtendable.swift */,
- D10B0EB05AA6B997D5B0C2BD95B7F0D1 /* ConstraintMakerFinalizable.swift */,
- 34A206653959B0FF746804314F156A55 /* ConstraintMakerPrioritizable.swift */,
- 08604283E18AF4DF7A4FD9107C1F37F3 /* ConstraintMakerRelatable.swift */,
- 14501D25D8F6E2B505819E760BA65A1C /* ConstraintMakerRelatable+Extensions.swift */,
- 19C76CB8A25B2C660EA75AFF6647676C /* ConstraintMultiplierTarget.swift */,
- AB861D7993575C07991739F9E7CA580E /* ConstraintOffsetTarget.swift */,
- AC43E26F2BCEC3F8A82A37251E167C22 /* ConstraintPriority.swift */,
- E7DB8EF4BB696608C1219972EEA178A0 /* ConstraintPriorityTarget.swift */,
- BAC455D0F3897E6701EC5A5EC5169024 /* ConstraintRelatableTarget.swift */,
- D1B3D76A156161A20CEC3824B6B09CC8 /* ConstraintRelation.swift */,
- 587F92D0AE85CB263F1149F5AAEE7C77 /* ConstraintView.swift */,
- 4EA184E57AC862564DDF1E17D31F0C15 /* ConstraintView+Extensions.swift */,
- 0B0AF40C15008F0D0D92D22AE55A25CF /* ConstraintViewDSL.swift */,
- 2E93F5EB563B0B1709714E647C1240BF /* Debugging.swift */,
- 594672ACD25BFC6E05E3BEDC0AFF20B6 /* LayoutConstraint.swift */,
- 8C289513B354447D46903A2D85C93AC8 /* LayoutConstraintItem.swift */,
- F431F8514500EB417A0B5D57D7C66A41 /* Typealiases.swift */,
- D360D2580F6F41C8ABE2606EB7A25C77 /* UILayoutSupport+Extensions.swift */,
- 05509D3D469F558F8658F676D8E4BCA2 /* Resources */,
- 0165B987DA4D81EB7DFC7EAEBFAABFBB /* Support Files */,
- );
- path = SnapKit;
- sourceTree = "<group>";
- };
- 4AA169456C15955E80368C5E8742E9F7 /* iOS */ = {
- isa = PBXGroup;
- children = (
- C94130B86B411D191585E6A223C3C694 /* CFNetwork.framework */,
- 71F2AFDF205411E56316964DE08D951E /* Foundation.framework */,
- 66549C441E7F0958A782198C074E2397 /* QuartzCore.framework */,
- 054C080A56516E4ADDA7E9FEEA2D4FD5 /* Security.framework */,
- );
- name = iOS;
- sourceTree = "<group>";
- };
- 5D86D48A3B789FF96DC016334C09ECA3 /* Products */ = {
- isa = PBXGroup;
- children = (
- D863F9DE61CFC7AA3F031CE3260FFE4D /* Pods_JoyGemAIDemo.framework */,
- 979486118B3E90C08386079D57962701 /* SnapKit.framework */,
- B9DCB5EC0B1CDADD221717CADDF62359 /* SnapKit_Privacy.bundle */,
- 85A01882ED06DFEA2E0CE78BCDB204A7 /* SocketRocket.framework */,
- E97D43C46A45EE515A4DA3AF94398441 /* SVProgressHUD.framework */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- 6E3F9B59595833EDA6318C22C7EBBDB9 /* Pods */ = {
- isa = PBXGroup;
- children = (
- 11A5B8FCBF685FD503D053A5E1B57B5A /* SnapKit */,
- E1AEAAC4191A62736E2FBFE444D87516 /* SocketRocket */,
- CC9E49E184BF8389723846DDD7CC17F2 /* SVProgressHUD */,
- );
- name = Pods;
- sourceTree = "<group>";
- };
- 70AEC151BB5CE1548F08FB4893DCF675 /* Pods-JoyGemAIDemo */ = {
- isa = PBXGroup;
- children = (
- 12B256489F57DB0D7209DFE5DDC0D705 /* Pods-JoyGemAIDemo.modulemap */,
- CDBBCEA019AFD586193D94A34E344E7A /* Pods-JoyGemAIDemo-acknowledgements.markdown */,
- 8D52542CF6C393E7708BED48E72DD679 /* Pods-JoyGemAIDemo-acknowledgements.plist */,
- 8A2D2C969321FF5F52A7272D95BCE8AC /* Pods-JoyGemAIDemo-dummy.m */,
- 030FEB9982732056707F3135743826F1 /* Pods-JoyGemAIDemo-frameworks.sh */,
- 38551E64867CE5BAFB66EC57CC2863F7 /* Pods-JoyGemAIDemo-Info.plist */,
- 4EE9B930126DDD3F7D558DDA0EC8A710 /* Pods-JoyGemAIDemo-umbrella.h */,
- 9A9313FF4398CEE1734CB6357724A7F1 /* Pods-JoyGemAIDemo.debug.xcconfig */,
- 93096358FB9D70A7A7498BAA812CCA52 /* Pods-JoyGemAIDemo.release.xcconfig */,
- );
- name = "Pods-JoyGemAIDemo";
- path = "Target Support Files/Pods-JoyGemAIDemo";
- sourceTree = "<group>";
- };
- 97120ED64FDA93A6C940E065CB7FAB64 /* Support Files */ = {
- isa = PBXGroup;
- children = (
- 2763F459D69C3B6B4108DE8ABA731567 /* SVProgressHUD.modulemap */,
- B03C9AC7EA6EBD11AA5CC20269FAF955 /* SVProgressHUD-dummy.m */,
- 55E5E095252D79C57304FFB017BB0BC5 /* SVProgressHUD-Info.plist */,
- 9B46A4A44CEAE7F06EDD05B954176D2C /* SVProgressHUD-prefix.pch */,
- D5BAD163B18A86FA28BB1B7FCDFDD532 /* SVProgressHUD-umbrella.h */,
- 925714E4666F0554718E983964951A8B /* SVProgressHUD.debug.xcconfig */,
- B2B52318F57059FC39EB5115B64E4FCF /* SVProgressHUD.release.xcconfig */,
- );
- name = "Support Files";
- path = "../Target Support Files/SVProgressHUD";
- sourceTree = "<group>";
- };
- BA4F31F07263C99FC76E66D632A59F09 /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 4AA169456C15955E80368C5E8742E9F7 /* iOS */,
- );
- name = Frameworks;
- sourceTree = "<group>";
- };
- BD049C321EB08EF29E658A3CBFC71BFE /* Support Files */ = {
- isa = PBXGroup;
- children = (
- F98682923B0BCA998E6618158F2101FB /* SocketRocket.modulemap */,
- 90FCF59C1DB50D4CF155EDD7974926E4 /* SocketRocket-dummy.m */,
- FE21277BF9017D281A07A338D5F51D92 /* SocketRocket-Info.plist */,
- 38A9A085D1DF5C3194ADEDC57264C009 /* SocketRocket-prefix.pch */,
- B9FD6FDF33FF7827E6C31546AB3EF28E /* SocketRocket-umbrella.h */,
- CC293BBB9A5E4968EE4ED5F611BF8162 /* SocketRocket.debug.xcconfig */,
- 8F23DB1C587B4583CD55800A55481EB6 /* SocketRocket.release.xcconfig */,
- );
- name = "Support Files";
- path = "../Target Support Files/SocketRocket";
- sourceTree = "<group>";
- };
- CC9E49E184BF8389723846DDD7CC17F2 /* SVProgressHUD */ = {
- isa = PBXGroup;
- children = (
- 00234441CF7C8CCEE3F7647B94F6BDAC /* Core */,
- 97120ED64FDA93A6C940E065CB7FAB64 /* Support Files */,
- );
- path = SVProgressHUD;
- sourceTree = "<group>";
- };
- CF1408CF629C7361332E53B88F7BD30C = {
- isa = PBXGroup;
- children = (
- 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */,
- BA4F31F07263C99FC76E66D632A59F09 /* Frameworks */,
- 6E3F9B59595833EDA6318C22C7EBBDB9 /* Pods */,
- 5D86D48A3B789FF96DC016334C09ECA3 /* Products */,
- FD4740BF40336DE04AC6CC902566FD50 /* Targets Support Files */,
- );
- sourceTree = "<group>";
- };
- E1AEAAC4191A62736E2FBFE444D87516 /* SocketRocket */ = {
- isa = PBXGroup;
- children = (
- 76BE51A7A16AD25A516A8FE62021D0E1 /* NSRunLoop+SRWebSocket.h */,
- 919D3078BD5668ACA389A35AD945CFCB /* NSRunLoop+SRWebSocket.m */,
- 4C94F20D2970D27EE685FDD11155161C /* NSRunLoop+SRWebSocketPrivate.h */,
- 577FF168360656D8723DCA6C8A4FFE94 /* NSURLRequest+SRWebSocket.h */,
- 63E65DF20C67826C4F05933C9C548DE0 /* NSURLRequest+SRWebSocket.m */,
- FDDAC95778CCFBCF273CB4E641A690E4 /* NSURLRequest+SRWebSocketPrivate.h */,
- 40E1C989D96D36B27BDFC28C0DF32C37 /* SocketRocket.h */,
- CC5847BA2AD63E1B9FC7263CAB3E2498 /* SRConstants.h */,
- 938BD9979B42CBFEC37273BC9C37A48C /* SRConstants.m */,
- 6C6A15EB1F466050C1436D7E1E47EAB1 /* SRDelegateController.h */,
- 185F6DDECC4865237EB7C1AE1B31056D /* SRDelegateController.m */,
- 4E80B99F422C47FAE83A9416F6E4DDC5 /* SRError.h */,
- E7774F4ADD0B69233B7E17979DF8D668 /* SRError.m */,
- 4C3A0C5D93DBB0A93DDFEEA897326433 /* SRHash.h */,
- EE49421E2F86071271A52B1FDC1BDD58 /* SRHash.m */,
- 572E05997DDC55370C47ED497255D8D3 /* SRHTTPConnectMessage.h */,
- 6BA0FDB8F2FF7D242A9C04D637F9395D /* SRHTTPConnectMessage.m */,
- 4B7C748554BBA7785B4D717CD5C2FDB6 /* SRIOConsumer.h */,
- 5560650533F07B36E06B6F96E4FFF307 /* SRIOConsumer.m */,
- 5C37DBED4411BB9A4E32119E2C48E33A /* SRIOConsumerPool.h */,
- EC5BE341F8DFE6872E5F64B48F725FC2 /* SRIOConsumerPool.m */,
- BF42198EDA662CDDE17107F36890BE2F /* SRLog.h */,
- 1BD1EE82BCA143564A9DEC60ADAC5504 /* SRLog.m */,
- B0DF85B6E4E98B26354EF0A3E5FEF528 /* SRMutex.h */,
- EA2411F3FE4D90B6D9BBABF80B5D9331 /* SRMutex.m */,
- 078A1E3C0A17D73D5696661F2FD41355 /* SRPinningSecurityPolicy.h */,
- 8381137A70938D1BBBB82AAFC63B0B1A /* SRPinningSecurityPolicy.m */,
- 20DCA1264B0FDE4CCC9B8EC324D8EC42 /* SRProxyConnect.h */,
- 19947805A4B09C6EE4C89FC2C66ADD61 /* SRProxyConnect.m */,
- 4CB86616CD8D64DBA9773C30C3AA41D6 /* SRRandom.h */,
- 89D9E3C762868F41C4BBA43E1778A7A5 /* SRRandom.m */,
- 85943BDD2DEECD3663D3A3BC6D684C1C /* SRRunLoopThread.h */,
- 64565DD0CD433588F260F50F66079582 /* SRRunLoopThread.m */,
- 31A63CD82C66679A09F23A5F4C655209 /* SRSecurityPolicy.h */,
- C3650C85CE8A8BF1751F13A8A21CC5E4 /* SRSecurityPolicy.m */,
- AEF784F41ECAE3C5470C7E86FEA09077 /* SRSIMDHelpers.h */,
- 11C7808696C7AD7D8B09BA7956749A18 /* SRSIMDHelpers.m */,
- 15F04AA9E58298DC3C28EEFD6F884C7B /* SRURLUtilities.h */,
- A45A1FC09B35C7FBB139B6D0B5BA9737 /* SRURLUtilities.m */,
- B907B14F3A53FFA2D4AC8BE9952962B7 /* SRWebSocket.h */,
- 97D9FEC2E67EC3B9B83E4A19175262BC /* SRWebSocket.m */,
- BD049C321EB08EF29E658A3CBFC71BFE /* Support Files */,
- );
- path = SocketRocket;
- sourceTree = "<group>";
- };
- EBDCD60CA22CA04B2A7F8036D19F82BF /* Resources */ = {
- isa = PBXGroup;
- children = (
- 23AD01048CEF57765D52B2EF4C55B397 /* PrivacyInfo.xcprivacy */,
- C982F402CB113B05D4B1F2A20FEE2040 /* SVProgressHUD.bundle */,
- );
- name = Resources;
- sourceTree = "<group>";
- };
- FD4740BF40336DE04AC6CC902566FD50 /* Targets Support Files */ = {
- isa = PBXGroup;
- children = (
- 70AEC151BB5CE1548F08FB4893DCF675 /* Pods-JoyGemAIDemo */,
- );
- name = "Targets Support Files";
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXHeadersBuildPhase section */
- 5B1500FE995B9224E0AF0B42CE93C03B /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 57C4F6EFB30DDD14E960AC2D6B34F904 /* SnapKit-umbrella.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 98612CDED433273F86F323607C2B579D /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- FBEDAA38D7E0B3C8DEE459EAA095C48C /* Pods-JoyGemAIDemo-umbrella.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- A440384545772625048C36C84242D128 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- B543A1E1882CAEA19589891FCE2D17EA /* NSRunLoop+SRWebSocket.h in Headers */,
- 3BB0B5D924BE769E95E64A5E6FC1675D /* NSRunLoop+SRWebSocketPrivate.h in Headers */,
- 56851E11140A140A15088A41DC4C33BD /* NSURLRequest+SRWebSocket.h in Headers */,
- 7174D48AADABCBE6FC53185C5442B952 /* NSURLRequest+SRWebSocketPrivate.h in Headers */,
- 07632D281C5DED61CC7866B079BC9D2C /* SocketRocket.h in Headers */,
- 5B67445AE2F3934BDA08D407BBA3028B /* SocketRocket-umbrella.h in Headers */,
- C92D93F48E74B79C08A2C5B81B68FD7D /* SRConstants.h in Headers */,
- EC8DB2CC9791B7DC686DCC78EFBB56C5 /* SRDelegateController.h in Headers */,
- 65E5693A457A8AEE3E5758075D1E2792 /* SRError.h in Headers */,
- F6E948E2688CC08D3843DAA74F6328E8 /* SRHash.h in Headers */,
- DF011D18EBB28ECE459B6D96D3E460D8 /* SRHTTPConnectMessage.h in Headers */,
- 9A3B9C740BC8FE0500132251551E5BE7 /* SRIOConsumer.h in Headers */,
- 44EFA9A76932F81582D03076A8346A4B /* SRIOConsumerPool.h in Headers */,
- 89CAC1E5DC5833EE630A652957D253A7 /* SRLog.h in Headers */,
- 782981022BF319DFD85AE89A392639A2 /* SRMutex.h in Headers */,
- 04986EEC139DC7C45DAB58056315FDC8 /* SRPinningSecurityPolicy.h in Headers */,
- 6464C345447C71904DA3706AACA3F55D /* SRProxyConnect.h in Headers */,
- C36214D8311B615CDA115276934926DC /* SRRandom.h in Headers */,
- 939EE0216FC02064B2F5894E87628182 /* SRRunLoopThread.h in Headers */,
- 2B7184BD487141C385B3CC3F3984AA55 /* SRSecurityPolicy.h in Headers */,
- 5DFD87881941225F0A5EAE64EB247708 /* SRSIMDHelpers.h in Headers */,
- 57A34E19799F03EB53206496FD362449 /* SRURLUtilities.h in Headers */,
- 444E95921E2BDCE7512867EAA1A6B381 /* SRWebSocket.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- FADE750CFF2C806685AE314EE7FF71B1 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 1739C4B63D12177E58B7110F21E939EB /* SVIndefiniteAnimatedView.h in Headers */,
- 14F6602F47FF59347CB6807CE217EDC5 /* SVProgressAnimatedView.h in Headers */,
- 91930FDB4F9CCBBA9789806D1611AE6F /* SVProgressHUD.h in Headers */,
- 6037BA6633BDFF4F63D6C8B7C70D6160 /* SVProgressHUD-umbrella.h in Headers */,
- 7804E0B3C98A2FE1E98AF544E88C9C3C /* SVRadialGradientLayer.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXHeadersBuildPhase section */
-
-/* Begin PBXNativeTarget section */
- 1948D0B63D2CF6A48E18B0B292BC6091 /* SocketRocket */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 698D46877F77FCD24D7D79E95A4A06D5 /* Build configuration list for PBXNativeTarget "SocketRocket" */;
- buildPhases = (
- A440384545772625048C36C84242D128 /* Headers */,
- 5B14979992C9DB89400DDFB2EB8B8ECB /* Sources */,
- 796567F81D938DA74DF71A2AFF3F8F3D /* Frameworks */,
- A540247F97F33E3F24D6C4B41FFA27DB /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = SocketRocket;
- productName = SocketRocket;
- productReference = 85A01882ED06DFEA2E0CE78BCDB204A7 /* SocketRocket.framework */;
- productType = "com.apple.product-type.framework";
- };
- 19622742EBA51E823D6DAE3F8CDBFAD4 /* SnapKit */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 80CE967CAA1D35721519F892BAF7A19B /* Build configuration list for PBXNativeTarget "SnapKit" */;
- buildPhases = (
- 5B1500FE995B9224E0AF0B42CE93C03B /* Headers */,
- F7AC6792C89443C7B212A06E810BAB97 /* Sources */,
- 33428AC36668E3ED52DB70316F843FB8 /* Frameworks */,
- 1DEDF411E550D85A1218E1655456A9CD /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- 520872BF964A7F09A45D9E60A00FF7C7 /* PBXTargetDependency */,
- );
- name = SnapKit;
- productName = SnapKit;
- productReference = 979486118B3E90C08386079D57962701 /* SnapKit.framework */;
- productType = "com.apple.product-type.framework";
- };
- 1C8D67D8B72D6BA42CCEDB648537A340 /* SVProgressHUD */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 69444753864BFEE93D93DCEABA3746A1 /* Build configuration list for PBXNativeTarget "SVProgressHUD" */;
- buildPhases = (
- FADE750CFF2C806685AE314EE7FF71B1 /* Headers */,
- 458ACEF2C06C471F7CFF2C2824CA0B34 /* Sources */,
- 58634B2196876B07B5310C7EACCF921E /* Frameworks */,
- 240039A2FB82D44B5CE5DB05D41F6BA9 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = SVProgressHUD;
- productName = SVProgressHUD;
- productReference = E97D43C46A45EE515A4DA3AF94398441 /* SVProgressHUD.framework */;
- productType = "com.apple.product-type.framework";
- };
- 8A8DB685241263AFDF5E6B20FE67B93A /* SnapKit-SnapKit_Privacy */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = F55BB91ADB9FCCFBB0980F63AA073317 /* Build configuration list for PBXNativeTarget "SnapKit-SnapKit_Privacy" */;
- buildPhases = (
- E3AF1CE77BB4FC6598CEC51A20D48A9B /* Sources */,
- 4B4CD810BB6E6D719ECFED6C6CA9C997 /* Frameworks */,
- 68ED73B0A5E4636019D5743C510C805E /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "SnapKit-SnapKit_Privacy";
- productName = SnapKit_Privacy;
- productReference = B9DCB5EC0B1CDADD221717CADDF62359 /* SnapKit_Privacy.bundle */;
- productType = "com.apple.product-type.bundle";
- };
- A292712D9B517D61D36A01A8ACB539E4 /* Pods-JoyGemAIDemo */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 29A6174BFC9EF989DA9D77553CEF1F9A /* Build configuration list for PBXNativeTarget "Pods-JoyGemAIDemo" */;
- buildPhases = (
- 98612CDED433273F86F323607C2B579D /* Headers */,
- BCDBBFDA5E0246EB6CA7430149DDB02C /* Sources */,
- 8CBA52A0E5D17C5026C3C675B65FA403 /* Frameworks */,
- 88A4AF5A2D6323D7CC924EA72A6E8652 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- 4AD4CED1A13727380BA9A18B1EDC8A09 /* PBXTargetDependency */,
- 23C86F95D374FB58DE6233F360D853F8 /* PBXTargetDependency */,
- AF7FA56ABD82159931F7B43641E7EC5F /* PBXTargetDependency */,
- );
- name = "Pods-JoyGemAIDemo";
- productName = Pods_JoyGemAIDemo;
- productReference = D863F9DE61CFC7AA3F031CE3260FFE4D /* Pods_JoyGemAIDemo.framework */;
- productType = "com.apple.product-type.framework";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- BFDFE7DC352907FC980B868725387E98 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- LastSwiftUpdateCheck = 1600;
- LastUpgradeCheck = 1600;
- };
- buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */;
- compatibilityVersion = "Xcode 16.0";
- developmentRegion = en;
- hasScannedForEncodings = 0;
- knownRegions = (
- Base,
- en,
- );
- mainGroup = CF1408CF629C7361332E53B88F7BD30C;
- productRefGroup = 5D86D48A3B789FF96DC016334C09ECA3 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- A292712D9B517D61D36A01A8ACB539E4 /* Pods-JoyGemAIDemo */,
- 19622742EBA51E823D6DAE3F8CDBFAD4 /* SnapKit */,
- 8A8DB685241263AFDF5E6B20FE67B93A /* SnapKit-SnapKit_Privacy */,
- 1948D0B63D2CF6A48E18B0B292BC6091 /* SocketRocket */,
- 1C8D67D8B72D6BA42CCEDB648537A340 /* SVProgressHUD */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 1DEDF411E550D85A1218E1655456A9CD /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 9E0045B41BFE697DB4ADE151228024D2 /* SnapKit_Privacy.bundle in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 240039A2FB82D44B5CE5DB05D41F6BA9 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 89717EC07E6324D3405867E754AE9131 /* PrivacyInfo.xcprivacy in Resources */,
- 7B0DD32902633C7FF95B5745D8322BC3 /* SVProgressHUD.bundle in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 68ED73B0A5E4636019D5743C510C805E /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 9FD199868823028AAB5681E3B7BFFB0E /* PrivacyInfo.xcprivacy in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 88A4AF5A2D6323D7CC924EA72A6E8652 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- A540247F97F33E3F24D6C4B41FFA27DB /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 458ACEF2C06C471F7CFF2C2824CA0B34 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- CEC96BA519484844D19338CC420C8808 /* SVIndefiniteAnimatedView.m in Sources */,
- E30E824D8CE04C815FAD7F424CF7C270 /* SVProgressAnimatedView.m in Sources */,
- F87D4D6C6668A4AA86232BA3BDB9A178 /* SVProgressHUD.m in Sources */,
- FB75853E6A0E0682E1000CFBD293EBBC /* SVProgressHUD-dummy.m in Sources */,
- 517CF33F75EA768ED4B7F0F440F54A7E /* SVRadialGradientLayer.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 5B14979992C9DB89400DDFB2EB8B8ECB /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 5E7E257AE5D618E46EF57A5818010F85 /* NSRunLoop+SRWebSocket.m in Sources */,
- 6645E9FB4265C5712E38055C931E1630 /* NSURLRequest+SRWebSocket.m in Sources */,
- A3585531EE4D8466B74A5A6F7958EC79 /* SocketRocket-dummy.m in Sources */,
- B893C0DD5BE32FAE1D6895E1ED392B7A /* SRConstants.m in Sources */,
- 1A117EC847E321871E40EB39F3576D11 /* SRDelegateController.m in Sources */,
- AB12501C57FFF722131F674ACB425944 /* SRError.m in Sources */,
- EB3BCE9B36BF814DA3069FA077168301 /* SRHash.m in Sources */,
- 0362BB03F32EC9FB6013DEE29E8E33EF /* SRHTTPConnectMessage.m in Sources */,
- FCFC8D5B48F3DC4BC8942320631D8C1B /* SRIOConsumer.m in Sources */,
- 20B8C7C05E3AF3032935F30500EF5550 /* SRIOConsumerPool.m in Sources */,
- CF6554D8A9380CAC0F51D5043769D930 /* SRLog.m in Sources */,
- A564D0B0EE8AED950D943A75C2B3092E /* SRMutex.m in Sources */,
- D25185C12789EA624C8BAC6A6432E77B /* SRPinningSecurityPolicy.m in Sources */,
- D623A6CB33709C4D87766C66A756A0F7 /* SRProxyConnect.m in Sources */,
- 9A3761D8CEFB0E2131D2EFA2DEBB3A99 /* SRRandom.m in Sources */,
- 92571FFBEF3A7B2F4F633624013010EE /* SRRunLoopThread.m in Sources */,
- 8D0D15CE4E92BA4433AE7EA578FE3E15 /* SRSecurityPolicy.m in Sources */,
- 6135798CCD656C1B3A6EA5738A23190A /* SRSIMDHelpers.m in Sources */,
- 7F30D73D46CAD9D21A25738B11A6DDDA /* SRURLUtilities.m in Sources */,
- 4DC15DC2DF3C4BBA344C86B112C9C68B /* SRWebSocket.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- BCDBBFDA5E0246EB6CA7430149DDB02C /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- ABC03808F32631C31667667948258ACE /* Pods-JoyGemAIDemo-dummy.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- E3AF1CE77BB4FC6598CEC51A20D48A9B /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- F7AC6792C89443C7B212A06E810BAB97 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 6E39129FC8643A70C276801FEF4C280D /* Constraint.swift in Sources */,
- 0CA7A132ABE7018DE9295456732F38BB /* ConstraintAttributes.swift in Sources */,
- F9EBA65892D78A31C068D727D84BCB88 /* ConstraintConfig.swift in Sources */,
- CE593943A9E7CF83822CF60304BCAD43 /* ConstraintConstantTarget.swift in Sources */,
- 7AF516B98D45391B909D507D0244104C /* ConstraintDescription.swift in Sources */,
- 1194E62AA3F6F506799B1A43B16942B5 /* ConstraintDirectionalInsets.swift in Sources */,
- E37671A03B4C17A1CF3766A6125833BB /* ConstraintDirectionalInsetTarget.swift in Sources */,
- 868A9F524A7985BDA1EA124D9BF4CA63 /* ConstraintDSL.swift in Sources */,
- AF760C78F1C7E11BF7CB9E9B29903530 /* ConstraintInsets.swift in Sources */,
- 2B2EB369550CE92CEEFCBFD3D32B8A3F /* ConstraintInsetTarget.swift in Sources */,
- 5922A6A0AE7152CF436356B3556F1835 /* ConstraintItem.swift in Sources */,
- 59F34874DA4ABB2F5C4E09EA6865936B /* ConstraintLayoutGuide.swift in Sources */,
- E3D779DEE753C0B0D33BA8E73A980265 /* ConstraintLayoutGuide+Extensions.swift in Sources */,
- 3D3B646B4988314275B40E97BEB16C7F /* ConstraintLayoutGuideDSL.swift in Sources */,
- B0875E3AB8718E7DFE5C53497C02A15E /* ConstraintLayoutSupport.swift in Sources */,
- 064D909CD827405E8DCC309DB1B7775A /* ConstraintLayoutSupportDSL.swift in Sources */,
- 4F4DEB687C0E4834A5B291DEE0651D6A /* ConstraintMaker.swift in Sources */,
- C14F10B663FE2898EACAB90C202B3F50 /* ConstraintMakerEditable.swift in Sources */,
- D4218DA55B2BA45937589200CC0DF1FB /* ConstraintMakerExtendable.swift in Sources */,
- B903049E7C1BED7918DAB208754107C7 /* ConstraintMakerFinalizable.swift in Sources */,
- AABEF13464BA7F4621BD94736C1D057C /* ConstraintMakerPrioritizable.swift in Sources */,
- BDA5C7CC91E86448237CF40954FAC5AF /* ConstraintMakerRelatable.swift in Sources */,
- 8BABA32F7B94A25D8E9208C0A8D90B2E /* ConstraintMakerRelatable+Extensions.swift in Sources */,
- 883EDEE1C699497CF2A77C3B8A32A790 /* ConstraintMultiplierTarget.swift in Sources */,
- 3577F172FA68CBAE47CFEE6FE25C5404 /* ConstraintOffsetTarget.swift in Sources */,
- 09E1F569A93FAD4B9149E30B9301F44A /* ConstraintPriority.swift in Sources */,
- DBA4803F4765E1650B8C6841157F5D73 /* ConstraintPriorityTarget.swift in Sources */,
- C07CB3E9A4D1BF00F841E4285629A2B2 /* ConstraintRelatableTarget.swift in Sources */,
- ECC5C2ADC2682F9171FEA22AF10DCE53 /* ConstraintRelation.swift in Sources */,
- 86CAB01D950C8BC35EDE0BDC01A2500B /* ConstraintView.swift in Sources */,
- 0DE5DB9C6227B3416778D8417DD95EA9 /* ConstraintView+Extensions.swift in Sources */,
- 7D42390CDB4FA147504B03DA2A174A0C /* ConstraintViewDSL.swift in Sources */,
- AE224EDB6D044C0FE86B086E950FC2F9 /* Debugging.swift in Sources */,
- BF1AE4D97E813B95C43EA4A298B973D1 /* LayoutConstraint.swift in Sources */,
- C6F45595676957ADBEC18EB3F23EAEC4 /* LayoutConstraintItem.swift in Sources */,
- BA2FB695DEB0D179253EEB8DFCE3578B /* SnapKit-dummy.m in Sources */,
- C6A4302ACE006C4E2CDD481287E2916B /* Typealiases.swift in Sources */,
- F6F33E8B268F3D41075374D95B8088DC /* UILayoutSupport+Extensions.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXTargetDependency section */
- 23C86F95D374FB58DE6233F360D853F8 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- name = SnapKit;
- target = 19622742EBA51E823D6DAE3F8CDBFAD4 /* SnapKit */;
- targetProxy = FD48D631BAD9713237222F94224B4230 /* PBXContainerItemProxy */;
- };
- 4AD4CED1A13727380BA9A18B1EDC8A09 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- name = SVProgressHUD;
- target = 1C8D67D8B72D6BA42CCEDB648537A340 /* SVProgressHUD */;
- targetProxy = A2037CAFBFB3B718C2AE2F4FB05B8705 /* PBXContainerItemProxy */;
- };
- 520872BF964A7F09A45D9E60A00FF7C7 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- name = "SnapKit-SnapKit_Privacy";
- target = 8A8DB685241263AFDF5E6B20FE67B93A /* SnapKit-SnapKit_Privacy */;
- targetProxy = C860B402EF6D807222EE55F2EA175448 /* PBXContainerItemProxy */;
- };
- AF7FA56ABD82159931F7B43641E7EC5F /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- name = SocketRocket;
- target = 1948D0B63D2CF6A48E18B0B292BC6091 /* SocketRocket */;
- targetProxy = 835DF671A580FED0D976A9BE52562532 /* PBXContainerItemProxy */;
- };
-/* End PBXTargetDependency section */
-
-/* Begin XCBuildConfiguration section */
- 243E47468B1AA86AEB11F03BA7A94E3A /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 7BA73F09977C922C7B7FA7C0B234E9E3 /* SnapKit.release.xcconfig */;
- buildSettings = {
- BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
- CLANG_ENABLE_OBJC_WEAK = NO;
- "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- ENABLE_MODULE_VERIFIER = NO;
- ENABLE_USER_SCRIPT_SANDBOXING = NO;
- GCC_PREFIX_HEADER = "Target Support Files/SnapKit/SnapKit-prefix.pch";
- GENERATE_INFOPLIST_FILE = NO;
- INFOPLIST_FILE = "Target Support Files/SnapKit/SnapKit-Info.plist";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- "@loader_path/Frameworks",
- );
- MARKETING_VERSION = 1.0;
- MODULEMAP_FILE = "Target Support Files/SnapKit/SnapKit.modulemap";
- MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
- PRODUCT_MODULE_NAME = SnapKit;
- PRODUCT_NAME = SnapKit;
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_INSTALL_OBJC_HEADER = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VALIDATE_PRODUCT = YES;
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Release;
- };
- 2E97CC1C8355042CF6D2B315FDABEA75 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 7BA73F09977C922C7B7FA7C0B234E9E3 /* SnapKit.release.xcconfig */;
- buildSettings = {
- CODE_SIGNING_ALLOWED = NO;
- CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/SnapKit";
- IBSC_MODULE = SnapKit;
- INFOPLIST_FILE = "Target Support Files/SnapKit/ResourceBundle-SnapKit_Privacy-SnapKit-Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
- PRODUCT_NAME = SnapKit_Privacy;
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- TARGETED_DEVICE_FAMILY = "1,2";
- WRAPPER_EXTENSION = bundle;
- };
- name = Release;
- };
- 3E89D47477058425C765DFFBF8BB0C33 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D137CAEEE2D408A7495FA50188CB4D52 /* SnapKit.debug.xcconfig */;
- buildSettings = {
- BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
- CLANG_ENABLE_OBJC_WEAK = NO;
- "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- ENABLE_MODULE_VERIFIER = NO;
- ENABLE_USER_SCRIPT_SANDBOXING = NO;
- GCC_PREFIX_HEADER = "Target Support Files/SnapKit/SnapKit-prefix.pch";
- GENERATE_INFOPLIST_FILE = NO;
- INFOPLIST_FILE = "Target Support Files/SnapKit/SnapKit-Info.plist";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- "@loader_path/Frameworks",
- );
- MARKETING_VERSION = 1.0;
- MODULEMAP_FILE = "Target Support Files/SnapKit/SnapKit.modulemap";
- MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
- PRODUCT_MODULE_NAME = SnapKit;
- PRODUCT_NAME = SnapKit;
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_INSTALL_OBJC_HEADER = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Debug;
- };
- 4146417E0A5EEF9CD061673E613C7D4E /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "POD_CONFIGURATION_RELEASE=1",
- "$(inherited)",
- );
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = NO;
- MTL_FAST_MATH = YES;
- PRODUCT_NAME = "$(TARGET_NAME)";
- STRIP_INSTALLED_PRODUCT = NO;
- SWIFT_COMPILATION_MODE = wholemodule;
- SWIFT_VERSION = 5.0;
- SYMROOT = "${SRCROOT}/../build";
- };
- name = Release;
- };
- 48AF7EB2069114CB866140B406C66503 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 93096358FB9D70A7A7498BAA812CCA52 /* Pods-JoyGemAIDemo.release.xcconfig */;
- buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
- BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
- CLANG_ENABLE_OBJC_WEAK = NO;
- "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- ENABLE_MODULE_VERIFIER = NO;
- ENABLE_USER_SCRIPT_SANDBOXING = NO;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_FILE = "Target Support Files/Pods-JoyGemAIDemo/Pods-JoyGemAIDemo-Info.plist";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- "@loader_path/Frameworks",
- );
- MACH_O_TYPE = staticlib;
- MARKETING_VERSION = 1.0;
- MODULEMAP_FILE = "Target Support Files/Pods-JoyGemAIDemo/Pods-JoyGemAIDemo.modulemap";
- MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
- OTHER_LDFLAGS = "";
- OTHER_LIBTOOLFLAGS = "";
- PODS_ROOT = "$(SRCROOT)";
- PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_INSTALL_OBJC_HEADER = NO;
- TARGETED_DEVICE_FAMILY = "1,2";
- VALIDATE_PRODUCT = YES;
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Release;
- };
- 5BD29E55997C2B25631D864E8E7AF45B /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = B2B52318F57059FC39EB5115B64E4FCF /* SVProgressHUD.release.xcconfig */;
- buildSettings = {
- CLANG_ENABLE_OBJC_WEAK = NO;
- "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- ENABLE_MODULE_VERIFIER = NO;
- ENABLE_USER_SCRIPT_SANDBOXING = NO;
- GCC_PREFIX_HEADER = "Target Support Files/SVProgressHUD/SVProgressHUD-prefix.pch";
- GENERATE_INFOPLIST_FILE = NO;
- INFOPLIST_FILE = "Target Support Files/SVProgressHUD/SVProgressHUD-Info.plist";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- "@loader_path/Frameworks",
- );
- MARKETING_VERSION = 1.0;
- MODULEMAP_FILE = "Target Support Files/SVProgressHUD/SVProgressHUD.modulemap";
- MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
- PRODUCT_MODULE_NAME = SVProgressHUD;
- PRODUCT_NAME = SVProgressHUD;
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_INSTALL_OBJC_HEADER = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VALIDATE_PRODUCT = YES;
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Release;
- };
- 5E48A05D0E3DCED9E5C0F1507DC1517E /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 8F23DB1C587B4583CD55800A55481EB6 /* SocketRocket.release.xcconfig */;
- buildSettings = {
- CLANG_ENABLE_OBJC_WEAK = NO;
- "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- ENABLE_MODULE_VERIFIER = NO;
- ENABLE_USER_SCRIPT_SANDBOXING = NO;
- GCC_PREFIX_HEADER = "Target Support Files/SocketRocket/SocketRocket-prefix.pch";
- GENERATE_INFOPLIST_FILE = NO;
- INFOPLIST_FILE = "Target Support Files/SocketRocket/SocketRocket-Info.plist";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- "@loader_path/Frameworks",
- );
- MARKETING_VERSION = 1.0;
- MODULEMAP_FILE = "Target Support Files/SocketRocket/SocketRocket.modulemap";
- MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
- PRODUCT_MODULE_NAME = SocketRocket;
- PRODUCT_NAME = SocketRocket;
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_INSTALL_OBJC_HEADER = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VALIDATE_PRODUCT = YES;
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Release;
- };
- 84B6A261A9603785947F8535D83CD6DC /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 9A9313FF4398CEE1734CB6357724A7F1 /* Pods-JoyGemAIDemo.debug.xcconfig */;
- buildSettings = {
- ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
- BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
- CLANG_ENABLE_OBJC_WEAK = NO;
- "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- ENABLE_MODULE_VERIFIER = NO;
- ENABLE_USER_SCRIPT_SANDBOXING = NO;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_FILE = "Target Support Files/Pods-JoyGemAIDemo/Pods-JoyGemAIDemo-Info.plist";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- "@loader_path/Frameworks",
- );
- MACH_O_TYPE = staticlib;
- MARKETING_VERSION = 1.0;
- MODULEMAP_FILE = "Target Support Files/Pods-JoyGemAIDemo/Pods-JoyGemAIDemo.modulemap";
- MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
- OTHER_LDFLAGS = "";
- OTHER_LIBTOOLFLAGS = "";
- PODS_ROOT = "$(SRCROOT)";
- PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
- PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_INSTALL_OBJC_HEADER = NO;
- TARGETED_DEVICE_FAMILY = "1,2";
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Debug;
- };
- 8EDDE50761E2BD694755FA38A2B7F264 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D137CAEEE2D408A7495FA50188CB4D52 /* SnapKit.debug.xcconfig */;
- buildSettings = {
- CODE_SIGNING_ALLOWED = NO;
- CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/SnapKit";
- IBSC_MODULE = SnapKit;
- INFOPLIST_FILE = "Target Support Files/SnapKit/ResourceBundle-SnapKit_Privacy-SnapKit-Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
- PRODUCT_NAME = SnapKit_Privacy;
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- TARGETED_DEVICE_FAMILY = "1,2";
- WRAPPER_EXTENSION = bundle;
- };
- name = Debug;
- };
- 8FA7A7481543B3DBB7E250B6A3372323 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
- CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- DEBUG_INFORMATION_FORMAT = dwarf;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- ENABLE_USER_SCRIPT_SANDBOXING = YES;
- GCC_C_LANGUAGE_STANDARD = gnu17;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "POD_CONFIGURATION_DEBUG=1",
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 13.0;
- LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
- MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- MTL_FAST_MATH = YES;
- ONLY_ACTIVE_ARCH = YES;
- PRODUCT_NAME = "$(TARGET_NAME)";
- STRIP_INSTALLED_PRODUCT = NO;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- SWIFT_VERSION = 5.0;
- SYMROOT = "${SRCROOT}/../build";
- };
- name = Debug;
- };
- A7D2C32586573154B17B858DF64FF000 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 925714E4666F0554718E983964951A8B /* SVProgressHUD.debug.xcconfig */;
- buildSettings = {
- CLANG_ENABLE_OBJC_WEAK = NO;
- "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- ENABLE_MODULE_VERIFIER = NO;
- ENABLE_USER_SCRIPT_SANDBOXING = NO;
- GCC_PREFIX_HEADER = "Target Support Files/SVProgressHUD/SVProgressHUD-prefix.pch";
- GENERATE_INFOPLIST_FILE = NO;
- INFOPLIST_FILE = "Target Support Files/SVProgressHUD/SVProgressHUD-Info.plist";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 12.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- "@loader_path/Frameworks",
- );
- MARKETING_VERSION = 1.0;
- MODULEMAP_FILE = "Target Support Files/SVProgressHUD/SVProgressHUD.modulemap";
- MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
- PRODUCT_MODULE_NAME = SVProgressHUD;
- PRODUCT_NAME = SVProgressHUD;
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_INSTALL_OBJC_HEADER = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Debug;
- };
- E257492C03FE874E4F85F9A1CEF19BFD /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = CC293BBB9A5E4968EE4ED5F611BF8162 /* SocketRocket.debug.xcconfig */;
- buildSettings = {
- CLANG_ENABLE_OBJC_WEAK = NO;
- "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
- "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
- CURRENT_PROJECT_VERSION = 1;
- DEFINES_MODULE = YES;
- DYLIB_COMPATIBILITY_VERSION = 1;
- DYLIB_CURRENT_VERSION = 1;
- DYLIB_INSTALL_NAME_BASE = "@rpath";
- ENABLE_MODULE_VERIFIER = NO;
- ENABLE_USER_SCRIPT_SANDBOXING = NO;
- GCC_PREFIX_HEADER = "Target Support Files/SocketRocket/SocketRocket-prefix.pch";
- GENERATE_INFOPLIST_FILE = NO;
- INFOPLIST_FILE = "Target Support Files/SocketRocket/SocketRocket-Info.plist";
- INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/Frameworks",
- "@loader_path/Frameworks",
- );
- MARKETING_VERSION = 1.0;
- MODULEMAP_FILE = "Target Support Files/SocketRocket/SocketRocket.modulemap";
- MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
- MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
- PRODUCT_MODULE_NAME = SocketRocket;
- PRODUCT_NAME = SocketRocket;
- SDKROOT = iphoneos;
- SKIP_INSTALL = YES;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) ";
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_INSTALL_OBJC_HEADER = YES;
- SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
- VERSIONING_SYSTEM = "apple-generic";
- VERSION_INFO_PREFIX = "";
- };
- name = Debug;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 29A6174BFC9EF989DA9D77553CEF1F9A /* Build configuration list for PBXNativeTarget "Pods-JoyGemAIDemo" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 84B6A261A9603785947F8535D83CD6DC /* Debug */,
- 48AF7EB2069114CB866140B406C66503 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 8FA7A7481543B3DBB7E250B6A3372323 /* Debug */,
- 4146417E0A5EEF9CD061673E613C7D4E /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 69444753864BFEE93D93DCEABA3746A1 /* Build configuration list for PBXNativeTarget "SVProgressHUD" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- A7D2C32586573154B17B858DF64FF000 /* Debug */,
- 5BD29E55997C2B25631D864E8E7AF45B /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 698D46877F77FCD24D7D79E95A4A06D5 /* Build configuration list for PBXNativeTarget "SocketRocket" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- E257492C03FE874E4F85F9A1CEF19BFD /* Debug */,
- 5E48A05D0E3DCED9E5C0F1507DC1517E /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 80CE967CAA1D35721519F892BAF7A19B /* Build configuration list for PBXNativeTarget "SnapKit" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 3E89D47477058425C765DFFBF8BB0C33 /* Debug */,
- 243E47468B1AA86AEB11F03BA7A94E3A /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- F55BB91ADB9FCCFBB0980F63AA073317 /* Build configuration list for PBXNativeTarget "SnapKit-SnapKit_Privacy" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 8EDDE50761E2BD694755FA38A2B7F264 /* Debug */,
- 2E97CC1C8355042CF6D2B315FDABEA75 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */;
-}
+++ /dev/null
-MIT License
-
-Copyright (c) 2011-2023 Sam Vermette, Tobias Totzek and contributors.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+++ /dev/null
-# SVProgressHUD
-
-
-
-
-[](https://swift.org/package-manager/)
-[](https://cocoapods.org)
-[](https://github.com/Carthage/Carthage)
-
-`SVProgressHUD` is a clean and easy-to-use HUD meant to display the progress of an ongoing task on iOS and tvOS.
-
-
-
-## Installation
-
-### Swift Package Manager
-
-[Swift Package Manager](https://swift.org/package-manager/) (SwiftPM) is a tool for managing the distribution of Swift code. It simplifies the process of managing Swift package dependencies.
-
-To integrate `SVProgressHUD` into your project using SwiftPM:
-
-1. In Xcode, select **File > Add Package Dependency**.
-2. Enter the following package repository URL: https://github.com/SVProgressHUD/SVProgressHUD.git
-3. Choose the appropriate version (e.g. a specific version, branch, or commit).
-4. Add `SVProgressHUD` to your target dependencies.
-
-`SVProgressHUD` requires at least Swift tools version 5.3.
-
-### From CocoaPods
-
-[CocoaPods](http://cocoapods.org) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like `SVProgressHUD` in your projects. First, add the following line to your [Podfile](http://guides.cocoapods.org/using/using-cocoapods.html):
-
-```ruby
-pod 'SVProgressHUD'
-```
-
-If you want to use the latest features of `SVProgressHUD` use normal external source dependencies.
-
-```ruby
-pod 'SVProgressHUD', :git => 'https://github.com/SVProgressHUD/SVProgressHUD.git'
-```
-
-This pulls from the `master` branch directly.
-
-Second, install `SVProgressHUD` into your project:
-
-```ruby
-pod install
-```
-
-### Carthage
-
-[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate `SVProgressHUD` into your Xcode project using Carthage, specify it in your `Cartfile`:
-
-```ogdl
-github "SVProgressHUD/SVProgressHUD"
-```
-
-Run `carthage bootstrap` to build the framework in your repository's Carthage directory. You can then include it in your target's `carthage copy-frameworks` build phase. For more information on this, please see [Carthage's documentation](https://github.com/carthage/carthage#if-youre-building-for-ios-tvos-or-watchos).
-
-### Manually
-
-* Drag the `SVProgressHUD/SVProgressHUD` folder into your project.
-* Take care that `SVProgressHUD.bundle` is added to `Targets->Build Phases->Copy Bundle Resources`.
-* Add the **QuartzCore** framework to your project.
-
-## Swift
-
-Even though `SVProgressHUD` is written in Objective-C, it can be used in Swift with no hassle.
-
-If you use [CocoaPods](http://cocoapods.org) add the following line to your [Podfile](http://guides.cocoapods.org/using/using-cocoapods.html):
-
-```ruby
-use_frameworks!
-```
-
-If you added `SVProgressHUD` manually, just add a [bridging header](https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html) file to your project with the `SVProgressHUD` header included.
-
-## Usage
-
-(see sample Xcode project in `/Demo`)
-
-`SVProgressHUD` is created as a singleton (i.e. it doesn't need to be explicitly allocated and instantiated; you directly call `[SVProgressHUD method]` / `SVProgressHUD.method()`).
-
-**Use `SVProgressHUD` wisely! Only use it if you absolutely need to perform a task before taking the user forward. Bad use case examples: pull to refresh, infinite scrolling, sending message.**
-
-Using `SVProgressHUD` in your app will usually look as simple as this.
-
-**Objective-C:**
-
-```objective-c
-[SVProgressHUD show];
-dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- // time-consuming task
- dispatch_async(dispatch_get_main_queue(), ^{
- [SVProgressHUD dismiss];
- });
-});
-```
-
-**Swift:**
-
-```swift
-SVProgressHUD.show()
-DispatchQueue.global(qos: .default).async {
- // time-consuming task
- DispatchQueue.main.async {
- SVProgressHUD.dismiss()
- }
-}
-```
-
-### Showing the HUD
-
-You can show the status of indeterminate tasks using one of the following:
-
-```objective-c
-+ (void)show;
-+ (void)showWithStatus:(NSString*)string;
-```
-
-If you'd like the HUD to reflect the progress of a task, use one of these:
-
-```objective-c
-+ (void)showProgress:(CGFloat)progress;
-+ (void)showProgress:(CGFloat)progress status:(NSString*)status;
-```
-
-### Dismissing the HUD
-
-The HUD can be dismissed using:
-
-```objective-c
-+ (void)dismiss;
-+ (void)dismissWithDelay:(NSTimeInterval)delay;
-```
-
-If you'd like to stack HUDs, you can balance out every show call using:
-
-```
-+ (void)popActivity;
-```
-
-The HUD will get dismissed once the `popActivity` calls will match the number of show calls.
-
-Or show an image with status before getting dismissed a little bit later. The display time depends on `minimumDismissTimeInterval` and the length of the given string.
-
-```objective-c
-+ (void)showInfoWithStatus:(NSString*)string;
-+ (void)showSuccessWithStatus:(NSString*)string;
-+ (void)showErrorWithStatus:(NSString*)string;
-+ (void)showImage:(UIImage*)image status:(NSString*)string;
-```
-
-## Customization
-
-`SVProgressHUD` is designed with flexibility in mind, providing a myriad of customization options to fit the look and feel of your application seamlessly.
-
-* Appearance: Make use of the `UI_APPEARANCE_SELECTOR` to adjust styles, colors, fonts, size, and images app-wide.
-* Behavior: Control visibility durations, display delays, and animation speeds.
-* Feedback: Enhance the user experience with options for haptic feedback and motion effects.
-
-For a comprehensive list of properties and detailed explanations, refer to the `SVProgressHUD.h` file in the API documentation.
-
-### Hint
-
-As standard `SVProgressHUD` offers three preconfigured styles:
-
-* `SVProgressHUDStyleAutomatic`: Automatically switch between the light and dark style
-* `SVProgressHUDStyleLight`: White background with black spinner and text
-* `SVProgressHUDStyleDark`: Black background with white spinner and text
-
-If you want to use custom colors use `setForegroundColor:` and/or `setBackgroundColor:`. These implicitly set the HUD's style to `SVProgressHUDStyleCustom`.
-
-## Haptic Feedback
-
-Available on iPhone 7 and newer, `SVProgressHUD` can automatically trigger haptic feedback depending on which HUD is being displayed. The feedback maps as follows:
-
-* `showSuccessWithStatus:` <-> `UINotificationFeedbackTypeSuccess`
-* `showInfoWithStatus:` <-> `UINotificationFeedbackTypeWarning`
-* `showErrorWithStatus:` <-> `UINotificationFeedbackTypeError`
-
-To enable this functionality, use `setHapticsEnabled:`.
-
-## Notifications
-
-`SVProgressHUD` posts four notifications via `NSNotificationCenter` in response to being shown/dismissed:
-
-* `SVProgressHUDWillAppearNotification` when the show animation starts
-* `SVProgressHUDDidAppearNotification` when the show animation completes
-* `SVProgressHUDWillDisappearNotification` when the dismiss animation starts
-* `SVProgressHUDDidDisappearNotification` when the dismiss animation completes
-
-Each notification passes a `userInfo` dictionary holding the HUD's status string (if any), retrievable via `SVProgressHUDStatusUserInfoKey`.
-
-`SVProgressHUD` also posts `SVProgressHUDDidReceiveTouchEventNotification` when users touch on the overall screen or `SVProgressHUDDidTouchDownInsideNotification` when a user touches on the HUD directly. For these notifications `userInfo` is not passed but the object parameter contains the `UIEvent` that related to the touch.
-
-## App Extensions
-
-When using `SVProgressHUD` in an App Extension, `#define SV_APP_EXTENSIONS` to avoid using unavailable APIs. This will be done automatically when using the `AppExtension` CocoaPods subspec. Additionally, call `setViewForExtension:` from your extensions view controller with `self.view`.
-
-## Contributing to this project
-
-If you have feature requests or bug reports, feel free to help out by sending pull requests or by [creating new issues](https://github.com/SVProgressHUD/SVProgressHUD/issues/new). Please take a moment to
-review the guidelines written by [Nicolas Gallagher](https://github.com/necolas):
-
-* [Bug reports](https://github.com/necolas/issue-guidelines/blob/master/CONTRIBUTING.md#bugs)
-* [Feature requests](https://github.com/necolas/issue-guidelines/blob/master/CONTRIBUTING.md#features)
-* [Pull requests](https://github.com/necolas/issue-guidelines/blob/master/CONTRIBUTING.md#pull-requests)
-
-## License
-
-`SVProgressHUD` is distributed under the terms and conditions of the [MIT license](https://github.com/SVProgressHUD/SVProgressHUD/blob/master/LICENSE). The success, error and info icons used on iOS 12 are made by [Freepik](http://www.freepik.com) from [Flaticon](https://www.flaticon.com) and are licensed under [Creative Commons BY 3.0](https://creativecommons.org/licenses/by/3.0/).
-
-## Privacy
-
-`SVProgressHUD` does not collect any data. A [privacy manifest file](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files) is [provided](SVProgressHUD/PrivacyInfo.xcprivacy).
-
-## Credits
-
-`SVProgressHUD` is brought to you by Sam Vermette, [Tobias Totzek](https://totzek.me) and [contributors to the project](https://github.com/SVProgressHUD/SVProgressHUD/contributors). If you're using `SVProgressHUD` in your project, attribution would be very appreciated.
+++ /dev/null
-<?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>NSPrivacyTracking</key>
- <false/>
- <key>NSPrivacyCollectedDataTypes</key>
- <array/>
- <key>NSPrivacyTrackingDomains</key>
- <array/>
- <key>NSPrivacyAccessedAPITypes</key>
- <array/>
-</dict>
-</plist>
+++ /dev/null
-//
-// SVIndefiniteAnimatedView.h
-// SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
-//
-// Copyright (c) 2014-2023 Guillaume Campagna and contributors. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface SVIndefiniteAnimatedView : UIView
-
-@property (nonatomic, assign) CGFloat strokeThickness;
-@property (nonatomic, assign) CGFloat radius;
-@property (nonatomic, strong) UIColor *strokeColor;
-
-@end
-
+++ /dev/null
-//
-// SVIndefiniteAnimatedView.m
-// SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
-//
-// Copyright (c) 2014-2023 Guillaume Campagna and contributors. All rights reserved.
-//
-
-#import "SVIndefiniteAnimatedView.h"
-#import "SVProgressHUD.h"
-
-@interface SVIndefiniteAnimatedView ()
-
-@property (nonatomic, strong) CAShapeLayer *indefiniteAnimatedLayer;
-
-@end
-
-@implementation SVIndefiniteAnimatedView
-
-- (void)willMoveToSuperview:(UIView*)newSuperview {
- if (newSuperview) {
- [self layoutAnimatedLayer];
- } else {
- [_indefiniteAnimatedLayer removeFromSuperlayer];
- _indefiniteAnimatedLayer = nil;
- }
-}
-
-- (void)layoutSubviews {
- [super layoutSubviews];
-
- [self layoutAnimatedLayer];
-}
-
-- (void)layoutAnimatedLayer {
- CALayer *layer = self.indefiniteAnimatedLayer;
-
- if (!layer.superlayer) {
- [self.layer addSublayer:layer];
- }
-
- CGFloat widthDiff = CGRectGetWidth(self.bounds) - CGRectGetWidth(layer.bounds);
- CGFloat heightDiff = CGRectGetHeight(self.bounds) - CGRectGetHeight(layer.bounds);
- layer.position = CGPointMake(CGRectGetWidth(self.bounds) - CGRectGetWidth(layer.bounds) / 2 - widthDiff / 2, CGRectGetHeight(self.bounds) - CGRectGetHeight(layer.bounds) / 2 - heightDiff / 2);
-}
-
-- (CAShapeLayer*)indefiniteAnimatedLayer {
- if(!_indefiniteAnimatedLayer) {
- CGPoint arcCenter = CGPointMake(self.radius+self.strokeThickness/2+5, self.radius+self.strokeThickness/2+5);
- UIBezierPath* smoothedPath = [UIBezierPath bezierPathWithArcCenter:arcCenter radius:self.radius startAngle:(CGFloat) (M_PI*3/2) endAngle:(CGFloat) (M_PI/2+M_PI*5) clockwise:YES];
-
- _indefiniteAnimatedLayer = [CAShapeLayer layer];
- _indefiniteAnimatedLayer.contentsScale = [[UIScreen mainScreen] scale];
- _indefiniteAnimatedLayer.frame = CGRectMake(0.0f, 0.0f, arcCenter.x*2, arcCenter.y*2);
- _indefiniteAnimatedLayer.fillColor = [UIColor clearColor].CGColor;
- _indefiniteAnimatedLayer.strokeColor = self.strokeColor.CGColor;
- _indefiniteAnimatedLayer.lineWidth = self.strokeThickness;
- _indefiniteAnimatedLayer.lineCap = kCALineCapRound;
- _indefiniteAnimatedLayer.lineJoin = kCALineJoinBevel;
- _indefiniteAnimatedLayer.path = smoothedPath.CGPath;
-
- CALayer *maskLayer = [CALayer layer];
-
- NSBundle *imageBundle = [SVProgressHUD imageBundle];
-
- maskLayer.contents = (__bridge id)[[UIImage imageNamed:@"angle-mask.png" inBundle:imageBundle compatibleWithTraitCollection:nil] CGImage];
- maskLayer.frame = _indefiniteAnimatedLayer.bounds;
- _indefiniteAnimatedLayer.mask = maskLayer;
-
- NSTimeInterval animationDuration = 1;
- CAMediaTimingFunction *linearCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
-
- CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
- animation.fromValue = (id) 0;
- animation.toValue = @(M_PI*2);
- animation.duration = animationDuration;
- animation.timingFunction = linearCurve;
- animation.removedOnCompletion = NO;
- animation.repeatCount = INFINITY;
- animation.fillMode = kCAFillModeForwards;
- animation.autoreverses = NO;
- [_indefiniteAnimatedLayer.mask addAnimation:animation forKey:@"rotate"];
-
- CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
- animationGroup.duration = animationDuration;
- animationGroup.repeatCount = INFINITY;
- animationGroup.removedOnCompletion = NO;
- animationGroup.timingFunction = linearCurve;
-
- CABasicAnimation *strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
- strokeStartAnimation.fromValue = @0.015;
- strokeStartAnimation.toValue = @0.515;
-
- CABasicAnimation *strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
- strokeEndAnimation.fromValue = @0.485;
- strokeEndAnimation.toValue = @0.985;
-
- animationGroup.animations = @[strokeStartAnimation, strokeEndAnimation];
- [_indefiniteAnimatedLayer addAnimation:animationGroup forKey:@"progress"];
-
- }
- return _indefiniteAnimatedLayer;
-}
-
-- (void)setFrame:(CGRect)frame {
- if(!CGRectEqualToRect(frame, super.frame)) {
- [super setFrame:frame];
-
- if(self.superview) {
- [self layoutAnimatedLayer];
- }
- }
-
-}
-
-- (void)setRadius:(CGFloat)radius {
- if(radius != _radius) {
- _radius = radius;
-
- [_indefiniteAnimatedLayer removeFromSuperlayer];
- _indefiniteAnimatedLayer = nil;
-
- if(self.superview) {
- [self layoutAnimatedLayer];
- }
- }
-}
-
-- (void)setStrokeColor:(UIColor*)strokeColor {
- _strokeColor = strokeColor;
- _indefiniteAnimatedLayer.strokeColor = strokeColor.CGColor;
-}
-
-- (void)setStrokeThickness:(CGFloat)strokeThickness {
- _strokeThickness = strokeThickness;
- _indefiniteAnimatedLayer.lineWidth = _strokeThickness;
-}
-
-- (CGSize)sizeThatFits:(CGSize)size {
- return CGSizeMake((self.radius+self.strokeThickness/2+5)*2, (self.radius+self.strokeThickness/2+5)*2);
-}
-
-@end
+++ /dev/null
-//
-// SVProgressAnimatedView.h
-// SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
-//
-// Copyright (c) 2017-2023 Tobias Totzek and contributors. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-
-@interface SVProgressAnimatedView : UIView
-
-@property (nonatomic, assign) CGFloat radius;
-@property (nonatomic, assign) CGFloat strokeThickness;
-@property (nonatomic, strong) UIColor *strokeColor;
-@property (nonatomic, assign) CGFloat strokeEnd;
-
-@end
+++ /dev/null
-//
-// SVProgressAnimatedView.m
-// SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
-//
-// Copyright (c) 2017-2023 Tobias Totzek and contributors. All rights reserved.
-//
-
-#import "SVProgressAnimatedView.h"
-
-@interface SVProgressAnimatedView ()
-
-@property (nonatomic, strong) CAShapeLayer *ringAnimatedLayer;
-
-@end
-
-@implementation SVProgressAnimatedView
-
-- (void)willMoveToSuperview:(UIView*)newSuperview {
- if (newSuperview) {
- [self layoutAnimatedLayer];
- } else {
- [_ringAnimatedLayer removeFromSuperlayer];
- _ringAnimatedLayer = nil;
- }
-}
-
-- (void)layoutAnimatedLayer {
- CALayer *layer = self.ringAnimatedLayer;
- [self.layer addSublayer:layer];
-
- CGFloat widthDiff = CGRectGetWidth(self.bounds) - CGRectGetWidth(layer.bounds);
- CGFloat heightDiff = CGRectGetHeight(self.bounds) - CGRectGetHeight(layer.bounds);
- layer.position = CGPointMake(CGRectGetWidth(self.bounds) - CGRectGetWidth(layer.bounds) / 2 - widthDiff / 2, CGRectGetHeight(self.bounds) - CGRectGetHeight(layer.bounds) / 2 - heightDiff / 2);
-}
-
-- (CAShapeLayer*)ringAnimatedLayer {
- if(!_ringAnimatedLayer) {
- CGPoint arcCenter = CGPointMake(self.radius+self.strokeThickness/2+5, self.radius+self.strokeThickness/2+5);
- UIBezierPath* smoothedPath = [UIBezierPath bezierPathWithArcCenter:arcCenter radius:self.radius startAngle:(CGFloat)-M_PI_2 endAngle:(CGFloat) (M_PI + M_PI_2) clockwise:YES];
-
- _ringAnimatedLayer = [CAShapeLayer layer];
- _ringAnimatedLayer.contentsScale = [[UIScreen mainScreen] scale];
- _ringAnimatedLayer.frame = CGRectMake(0.0f, 0.0f, arcCenter.x*2, arcCenter.y*2);
- _ringAnimatedLayer.fillColor = [UIColor clearColor].CGColor;
- _ringAnimatedLayer.strokeColor = self.strokeColor.CGColor;
- _ringAnimatedLayer.lineWidth = self.strokeThickness;
- _ringAnimatedLayer.lineCap = kCALineCapRound;
- _ringAnimatedLayer.lineJoin = kCALineJoinBevel;
- _ringAnimatedLayer.path = smoothedPath.CGPath;
- }
- return _ringAnimatedLayer;
-}
-
-- (void)setFrame:(CGRect)frame {
- if(!CGRectEqualToRect(frame, super.frame)) {
- [super setFrame:frame];
-
- if(self.superview) {
- [self layoutAnimatedLayer];
- }
- }
-}
-
-- (void)setRadius:(CGFloat)radius {
- if(radius != _radius) {
- _radius = radius;
-
- [_ringAnimatedLayer removeFromSuperlayer];
- _ringAnimatedLayer = nil;
-
- if(self.superview) {
- [self layoutAnimatedLayer];
- }
- }
-}
-
-- (void)setStrokeColor:(UIColor*)strokeColor {
- _strokeColor = strokeColor;
- _ringAnimatedLayer.strokeColor = strokeColor.CGColor;
-}
-
-- (void)setStrokeThickness:(CGFloat)strokeThickness {
- _strokeThickness = strokeThickness;
- _ringAnimatedLayer.lineWidth = _strokeThickness;
-}
-
-- (void)setStrokeEnd:(CGFloat)strokeEnd {
- _strokeEnd = strokeEnd;
- _ringAnimatedLayer.strokeEnd = _strokeEnd;
-}
-
-- (CGSize)sizeThatFits:(CGSize)size {
- return CGSizeMake((self.radius+self.strokeThickness/2+5)*2, (self.radius+self.strokeThickness/2+5)*2);
-}
-
-@end
+++ /dev/null
-//
-// SVProgressHUD.h
-// SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
-//
-// Copyright (c) 2011-2023 Sam Vermette and contributors. All rights reserved.
-//
-
-#import <UIKit/UIKit.h>
-#import <AvailabilityMacros.h>
-
-extern NSString * _Nonnull const SVProgressHUDDidReceiveTouchEventNotification;
-extern NSString * _Nonnull const SVProgressHUDDidTouchDownInsideNotification;
-extern NSString * _Nonnull const SVProgressHUDWillDisappearNotification;
-extern NSString * _Nonnull const SVProgressHUDDidDisappearNotification;
-extern NSString * _Nonnull const SVProgressHUDWillAppearNotification;
-extern NSString * _Nonnull const SVProgressHUDDidAppearNotification;
-
-extern NSString * _Nonnull const SVProgressHUDStatusUserInfoKey;
-
-/// Represents the appearance style of the HUD.
-typedef NS_ENUM(NSInteger, SVProgressHUDStyle) {
- /// White HUD with black text. HUD background will be blurred.
- SVProgressHUDStyleLight NS_SWIFT_NAME(light),
-
- /// Black HUD with white text. HUD background will be blurred.
- SVProgressHUDStyleDark NS_SWIFT_NAME(dark),
-
- /// Uses the fore- and background color properties.
- SVProgressHUDStyleCustom NS_SWIFT_NAME(custom),
-
- /// Automatically switch between light or dark mode appearance.
- SVProgressHUDStyleAutomatic NS_SWIFT_NAME(automatic)
-};
-
-/// Represents the type of mask to be applied when the HUD is displayed.
-typedef NS_ENUM(NSUInteger, SVProgressHUDMaskType) {
- /// Allow user interactions while HUD is displayed.
- SVProgressHUDMaskTypeNone NS_SWIFT_NAME(none) = 1,
-
- /// Don't allow user interactions with background objects.
- SVProgressHUDMaskTypeClear NS_SWIFT_NAME(clear),
-
- /// Don't allow user interactions and dim the UI behind the HUD (as in iOS 7+).
- SVProgressHUDMaskTypeBlack NS_SWIFT_NAME(black),
-
- /// Don't allow user interactions and dim the UI with an UIAlertView-like background gradient (as in iOS 6).
- SVProgressHUDMaskTypeGradient NS_SWIFT_NAME(gradient),
-
- /// Don't allow user interactions and dim the UI behind the HUD with a custom color.
- SVProgressHUDMaskTypeCustom NS_SWIFT_NAME(custom)
-};
-
-/// Represents the animation type of the HUD when it's shown or hidden.
-typedef NS_ENUM(NSUInteger, SVProgressHUDAnimationType) {
- /// Custom flat animation (indefinite animated ring).
- SVProgressHUDAnimationTypeFlat NS_SWIFT_NAME(flat),
-
- /// iOS native UIActivityIndicatorView.
- SVProgressHUDAnimationTypeNative NS_SWIFT_NAME(native)
-};
-
-typedef void (^SVProgressHUDShowCompletion)(void);
-typedef void (^SVProgressHUDDismissCompletion)(void);
-
-@interface SVProgressHUD : UIView
-
-#pragma mark - Customization
-
-/// Represents the default style for the HUD.
-/// @discussion Default: SVProgressHUDStyleAutomatic.
-@property (assign, nonatomic) SVProgressHUDStyle defaultStyle UI_APPEARANCE_SELECTOR;
-
-/// Represents the type of mask applied when the HUD is displayed.
-/// @discussion Default: SVProgressHUDMaskTypeNone.
-@property (assign, nonatomic) SVProgressHUDMaskType defaultMaskType UI_APPEARANCE_SELECTOR;
-
-/// Defines the animation type used when the HUD is displayed.
-/// @discussion Default: SVProgressHUDAnimationTypeFlat.
-@property (assign, nonatomic) SVProgressHUDAnimationType defaultAnimationType UI_APPEARANCE_SELECTOR;
-
-/// The container view used for displaying the HUD. If nil, the default window level is used.
-@property (strong, nonatomic, nullable) UIView *containerView;
-
-/// The minimum size for the HUD. Useful for maintaining a consistent size when the message might cause resizing.
-/// @discussion Default: CGSizeZero.
-@property (assign, nonatomic) CGSize minimumSize UI_APPEARANCE_SELECTOR;
-
-/// Thickness of the ring shown in the HUD.
-/// @discussion Default: 2 pt.
-@property (assign, nonatomic) CGFloat ringThickness UI_APPEARANCE_SELECTOR;
-
-/// Radius of the ring shown in the HUD when there's associated text.
-/// @discussion Default: 18 pt.
-@property (assign, nonatomic) CGFloat ringRadius UI_APPEARANCE_SELECTOR;
-
-/// Radius of the ring shown in the HUD when there's no associated text.
-/// @discussion Default: 24 pt.
-@property (assign, nonatomic) CGFloat ringNoTextRadius UI_APPEARANCE_SELECTOR;
-
-/// Corner radius of the HUD view.
-/// @discussion Default: 14 pt.
-@property (assign, nonatomic) CGFloat cornerRadius UI_APPEARANCE_SELECTOR;
-
-/// Font used for text within the HUD.
-/// @discussion Default: [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline].
-@property (strong, nonatomic, nonnull) UIFont *font UI_APPEARANCE_SELECTOR;
-
-/// Background color of the HUD.
-/// @discussion Default: [UIColor whiteColor].
-@property (strong, nonatomic, nonnull) UIColor *backgroundColor UI_APPEARANCE_SELECTOR;
-
-/// Foreground color used for content in the HUD.
-/// @discussion Default: [UIColor blackColor].
-@property (strong, nonatomic, nonnull) UIColor *foregroundColor UI_APPEARANCE_SELECTOR;
-
-/// Color for any foreground images in the HUD.
-/// @discussion Default: same as foregroundColor.
-@property (strong, nonatomic, nullable) UIColor *foregroundImageColor UI_APPEARANCE_SELECTOR;
-
-/// Color for the background layer behind the HUD.
-/// @discussion Default: [UIColor colorWithWhite:0 alpha:0.4].
-@property (strong, nonatomic, nonnull) UIColor *backgroundLayerColor UI_APPEARANCE_SELECTOR;
-
-/// Size of any images displayed within the HUD.
-/// @discussion Default: 28x28 pt.
-@property (assign, nonatomic) CGSize imageViewSize UI_APPEARANCE_SELECTOR;
-
-/// Indicates whether images within the HUD should be tinted.
-/// @discussion Default: YES.
-@property (assign, nonatomic) BOOL shouldTintImages UI_APPEARANCE_SELECTOR;
-
-/// The image displayed when showing informational messages.
-/// @discussion Default: info.circle from SF Symbols (iOS 13+) or the bundled info image provided by Freepik.
-@property (strong, nonatomic, nonnull) UIImage *infoImage UI_APPEARANCE_SELECTOR;
-
-/// The image displayed when showing success messages.
-/// @discussion Default: checkmark from SF Symbols (iOS 13+) or the bundled success image provided by Freepik.
-@property (strong, nonatomic, nonnull) UIImage *successImage UI_APPEARANCE_SELECTOR;
-
-/// The image displayed when showing error messages.
-/// @discussion Default: xmark from SF Symbols (iOS 13+) or the bundled error image provided by Freepik.
-@property (strong, nonatomic, nonnull) UIImage *errorImage UI_APPEARANCE_SELECTOR;
-
-/// A specific view for extensions. This property is only used if #define SV_APP_EXTENSIONS is set.
-/// @discussion Default: nil.
-@property (strong, nonatomic, nonnull) UIView *viewForExtension UI_APPEARANCE_SELECTOR;
-
-/// The interval in seconds to wait before displaying the HUD. If the HUD is displayed before this time elapses, this timer is reset.
-/// @discussion Default: 0 seconds.
-@property (assign, nonatomic) NSTimeInterval graceTimeInterval;
-
-/// The minimum amount of time in seconds the HUD will display.
-/// @discussion Default: 5.0 seconds.
-@property (assign, nonatomic) NSTimeInterval minimumDismissTimeInterval;
-
-/// The maximum amount of time in seconds the HUD will display.
-/// @discussion Default: CGFLOAT_MAX.
-@property (assign, nonatomic) NSTimeInterval maximumDismissTimeInterval;
-
-/// Offset from the center position, can be used to adjust the HUD position.
-/// @discussion Default: 0, 0.
-@property (assign, nonatomic) UIOffset offsetFromCenter UI_APPEARANCE_SELECTOR;
-
-/// Duration of the fade-in animation when showing the HUD.
-/// @discussion Default: 0.15.
-@property (assign, nonatomic) NSTimeInterval fadeInAnimationDuration UI_APPEARANCE_SELECTOR;
-
-/// Duration of the fade-out animation when hiding the HUD.
-/// @discussion Default: 0.15.
-@property (assign, nonatomic) NSTimeInterval fadeOutAnimationDuration UI_APPEARANCE_SELECTOR;
-
-/// The maximum window level on which the HUD can be displayed.
-/// @discussion Default: UIWindowLevelNormal.
-@property (assign, nonatomic) UIWindowLevel maxSupportedWindowLevel;
-
-/// Indicates if haptic feedback should be used.
-/// @discussion Default: NO.
-@property (assign, nonatomic) BOOL hapticsEnabled;
-
-/// Indicates if motion effects should be applied to the HUD.
-/// @discussion Default: YES.
-@property (assign, nonatomic) BOOL motionEffectEnabled;
-
-@property (class, strong, nonatomic, readonly, nonnull) NSBundle *imageBundle;
-
-/// Sets the default style for the HUD.
-/// @param style The desired style for the HUD.
-+ (void)setDefaultStyle:(SVProgressHUDStyle)style;
-
-/// Sets the default mask type for the HUD.
-/// @param maskType The mask type to apply.
-+ (void)setDefaultMaskType:(SVProgressHUDMaskType)maskType;
-
-/// Sets the default animation type for the HUD.
-/// @param type The desired animation type.
-+ (void)setDefaultAnimationType:(SVProgressHUDAnimationType)type;
-
-/// Sets the container view for the HUD.
-/// @param containerView The view to contain the HUD.
-+ (void)setContainerView:(nullable UIView*)containerView;
-
-/// Sets the minimum size for the HUD.
-/// @param minimumSize The minimum size for the HUD.
-+ (void)setMinimumSize:(CGSize)minimumSize;
-
-/// Sets the ring thickness for the HUD.
-/// @param ringThickness Thickness of the ring.
-+ (void)setRingThickness:(CGFloat)ringThickness;
-
-/// Sets the ring radius for the HUD.
-/// @param radius Radius of the ring.
-+ (void)setRingRadius:(CGFloat)radius;
-
-/// Sets the no text ring radius for the HUD.
-/// @param radius Radius of the ring when no text is displayed.
-+ (void)setRingNoTextRadius:(CGFloat)radius;
-
-/// Sets the corner radius for the HUD.
-/// @param cornerRadius Desired corner radius.
-+ (void)setCornerRadius:(CGFloat)cornerRadius;
-
-/// Sets the border color for the HUD.
-/// @param color Desired border color.
-+ (void)setBorderColor:(nonnull UIColor*)color;
-
-/// Sets the border width for the HUD.
-/// @param width Desired border width.
-+ (void)setBorderWidth:(CGFloat)width;
-
-/// Sets the font for the HUD's text.
-/// @param font Desired font for the text.
-+ (void)setFont:(nonnull UIFont*)font;
-
-/// Sets the foreground color for the HUD.
-/// @param color Desired foreground color.
-/// @discussion These implicitly set the HUD's style to `SVProgressHUDStyleCustom`.
-+ (void)setForegroundColor:(nonnull UIColor*)color;
-
-/// Sets the foreground image color for the HUD.
-/// @param color Desired color for the image.
-/// @discussion These implicitly set the HUD's style to `SVProgressHUDStyleCustom`.
-+ (void)setForegroundImageColor:(nullable UIColor*)color;
-
-/// Sets the background color for the HUD.
-/// @param color Desired background color.
-/// @discussion These implicitly set the HUD's style to `SVProgressHUDStyleCustom`.
-+ (void)setBackgroundColor:(nonnull UIColor*)color;
-
-/// Sets a custom blur effect for the HUD view.
-/// @param blurEffect Desired blur effect.
-/// @discussion These implicitly set the HUD's style to `SVProgressHUDStyleCustom`.
-+ (void)setHudViewCustomBlurEffect:(nullable UIBlurEffect*)blurEffect;
-
-/// Sets the background layer color for the HUD.
-/// @param color Desired color for the background layer.
-+ (void)setBackgroundLayerColor:(nonnull UIColor*)color;
-
-/// Sets the size for the HUD's image view.
-/// @param size Desired size for the image view.
-+ (void)setImageViewSize:(CGSize)size;
-
-/// Determines if images should be tinted in the HUD.
-/// @param shouldTintImages Whether images should be tinted.
-+ (void)setShouldTintImages:(BOOL)shouldTintImages;
-
-/// Sets the info image for the HUD.
-/// @param image The desired info image.
-+ (void)setInfoImage:(nonnull UIImage*)image;
-
-/// Sets the success image for the HUD.
-/// @param image The desired success image.
-+ (void)setSuccessImage:(nonnull UIImage*)image;
-
-/// Sets the error image for the HUD.
-/// @param image The desired error image.
-+ (void)setErrorImage:(nonnull UIImage*)image;
-
-/// Sets the view for extensions.
-/// @param view The desired view for extensions.
-+ (void)setViewForExtension:(nonnull UIView*)view;
-
-/// Sets the grace time interval for the HUD.
-/// @param interval Desired grace time interval.
-+ (void)setGraceTimeInterval:(NSTimeInterval)interval;
-
-/// Sets the minimum dismiss time interval.
-/// @param interval The minimum time interval, in seconds, that the HUD should be displayed.
-+ (void)setMinimumDismissTimeInterval:(NSTimeInterval)interval;
-
-/// Sets the maximum dismiss time interval.
-/// @param interval The maximum time interval, in seconds, that the HUD should be displayed.
-+ (void)setMaximumDismissTimeInterval:(NSTimeInterval)interval;
-
-/// Sets the fade-in animation duration.
-/// @param duration The duration, in seconds, for the fade-in animation.
-+ (void)setFadeInAnimationDuration:(NSTimeInterval)duration;
-
-/// Sets the fade-out animation duration.
-/// @param duration The duration, in seconds, for the fade-out animation.
-+ (void)setFadeOutAnimationDuration:(NSTimeInterval)duration;
-
-/// Sets the max supported window level.
-/// @param windowLevel The UIWindowLevel to which the HUD should be displayed.
-+ (void)setMaxSupportedWindowLevel:(UIWindowLevel)windowLevel;
-
-/// Determines if haptics are enabled.
-/// @param hapticsEnabled A boolean that determines if haptic feedback is enabled.
-+ (void)setHapticsEnabled:(BOOL)hapticsEnabled;
-
-/// Determines if motion effect is enabled.
-/// @param motionEffectEnabled A boolean that determines if motion effects are enabled.
-+ (void)setMotionEffectEnabled:(BOOL)motionEffectEnabled;
-
-
-#pragma mark - Show Methods
-
-/// Shows the HUD without any additional status message.
-+ (void)show;
-
-/// Shows the HUD with a provided status message.
-/// @param status The message to be displayed alongside the HUD.
-+ (void)showWithStatus:(nullable NSString*)status;
-
-/// Display methods to show progress on the HUD.
-
-/// Shows the HUD with a progress indicator.
-/// @param progress A float value between 0.0 and 1.0 indicating the progress.
-+ (void)showProgress:(float)progress;
-
-/// Shows the HUD with a progress indicator and a provided status message.
-/// @param progress A float value between 0.0 and 1.0 indicating the progress.
-/// @param status The message to be displayed alongside the progress indicator.
-+ (void)showProgress:(float)progress status:(nullable NSString*)status;
-
-/// Updates the current status of the loading HUD.
-/// @param status The new status message to update the HUD with.
-+ (void)setStatus:(nullable NSString*)status;
-
-/// Shows an info status with the provided message.
-/// @param status The info message to be displayed.
-+ (void)showInfoWithStatus:(nullable NSString*)status;
-
-/// Shows a success status with the provided message.
-/// @param status The success message to be displayed.
-+ (void)showSuccessWithStatus:(nullable NSString*)status;
-
-/// Shows an error status with the provided message.
-/// @param status The error message to be displayed.
-+ (void)showErrorWithStatus:(nullable NSString*)status;
-
-/// Shows a custom image with the provided status message.
-/// @param image The custom image to be displayed.
-/// @param status The message to accompany the custom image.
-+ (void)showImage:(nonnull UIImage*)image status:(nullable NSString*)status;
-
-/// Sets the offset from the center for the HUD.
-/// @param offset The UIOffset value indicating how much the HUD should be offset from its center position.
-+ (void)setOffsetFromCenter:(UIOffset)offset;
-
-/// Resets the offset to center the HUD.
-+ (void)resetOffsetFromCenter;
-
-/// Decreases the activity count, dismissing the HUD if count reaches 0.
-+ (void)popActivity;
-
-/// Dismisses the HUD immediately.
-+ (void)dismiss;
-
-/// Dismisses the HUD and triggers a completion block.
-/// @param completion A block that gets executed after the HUD is dismissed.
-+ (void)dismissWithCompletion:(nullable SVProgressHUDDismissCompletion)completion;
-
-/// Dismisses the HUD after a specified delay.
-/// @param delay The time in seconds after which the HUD should be dismissed.
-+ (void)dismissWithDelay:(NSTimeInterval)delay;
-
-/// Dismisses the HUD after a specified delay and triggers a completion block.
-/// @param delay The time in seconds after which the HUD should be dismissed.
-/// @param completion A block that gets executed after the HUD is dismissed.
-+ (void)dismissWithDelay:(NSTimeInterval)delay completion:(nullable SVProgressHUDDismissCompletion)completion;
-
-/// Checks if the HUD is currently visible.
-/// @return A boolean value indicating whether the HUD is visible.
-+ (BOOL)isVisible;
-
-/// Calculates the display duration based on a given string's length.
-/// @param string The string whose length determines the display duration.
-/// @return A time interval representing the display duration.
-+ (NSTimeInterval)displayDurationForString:(nullable NSString*)string;
-
-@end
-
+++ /dev/null
-//
-// SVProgressHUD.h
-// SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
-//
-// Copyright (c) 2011-2023 Sam Vermette and contributors. All rights reserved.
-//
-
-#if !__has_feature(objc_arc)
-#error SVProgressHUD is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
-#endif
-
-#import "SVProgressHUD.h"
-#import "SVIndefiniteAnimatedView.h"
-#import "SVProgressAnimatedView.h"
-#import "SVRadialGradientLayer.h"
-
-NSString * const SVProgressHUDDidReceiveTouchEventNotification = @"SVProgressHUDDidReceiveTouchEventNotification";
-NSString * const SVProgressHUDDidTouchDownInsideNotification = @"SVProgressHUDDidTouchDownInsideNotification";
-NSString * const SVProgressHUDWillDisappearNotification = @"SVProgressHUDWillDisappearNotification";
-NSString * const SVProgressHUDDidDisappearNotification = @"SVProgressHUDDidDisappearNotification";
-NSString * const SVProgressHUDWillAppearNotification = @"SVProgressHUDWillAppearNotification";
-NSString * const SVProgressHUDDidAppearNotification = @"SVProgressHUDDidAppearNotification";
-
-NSString * const SVProgressHUDStatusUserInfoKey = @"SVProgressHUDStatusUserInfoKey";
-
-static const CGFloat SVProgressHUDParallaxDepthPoints = 10.0f;
-static const CGFloat SVProgressHUDUndefinedProgress = -1;
-static const CGFloat SVProgressHUDDefaultAnimationDuration = 0.15f;
-static const CGFloat SVProgressHUDVerticalSpacing = 12.0f;
-static const CGFloat SVProgressHUDHorizontalSpacing = 12.0f;
-static const CGFloat SVProgressHUDLabelSpacing = 8.0f;
-
-
-@interface SVProgressHUD ()
-
-@property (nonatomic, strong) NSTimer *graceTimer;
-@property (nonatomic, strong) NSTimer *fadeOutTimer;
-
-@property (nonatomic, strong) UIControl *controlView;
-@property (nonatomic, strong) UIView *backgroundView;
-@property (nonatomic, strong) SVRadialGradientLayer *backgroundRadialGradientLayer;
-@property (nonatomic, strong) UIVisualEffectView *hudView;
-@property (nonatomic, strong) UIBlurEffect *hudViewCustomBlurEffect;
-@property (nonatomic, strong) UILabel *statusLabel;
-@property (nonatomic, strong) UIImageView *imageView;
-
-@property (nonatomic, strong) UIView *indefiniteAnimatedView;
-@property (nonatomic, strong) SVProgressAnimatedView *ringView;
-@property (nonatomic, strong) SVProgressAnimatedView *backgroundRingView;
-
-@property (nonatomic, readwrite) CGFloat progress;
-@property (nonatomic, readwrite) NSUInteger activityCount;
-
-@property (nonatomic, readonly) CGFloat visibleKeyboardHeight;
-@property (nonatomic, readonly) UIWindow *frontWindow;
-
-#if TARGET_OS_IOS
-@property (nonatomic, strong) UINotificationFeedbackGenerator *hapticGenerator;
-#endif
-
-@end
-
-@implementation SVProgressHUD {
- BOOL _isInitializing;
-}
-
-+ (SVProgressHUD*)sharedView {
- static dispatch_once_t once;
-
- static SVProgressHUD *sharedView;
-#if !defined(SV_APP_EXTENSIONS)
- dispatch_once(&once, ^{ sharedView = [[self alloc] initWithFrame:[SVProgressHUD mainWindow].bounds]; });
-#else
- dispatch_once(&once, ^{ sharedView = [[self alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; });
-#endif
- return sharedView;
-}
-
-+ (UIWindow *)mainWindow {
- if (@available(iOS 13.0, *)) {
- for (UIWindowScene* windowScene in [UIApplication sharedApplication].connectedScenes) {
- if (windowScene.activationState == UISceneActivationStateForegroundActive) {
- return windowScene.windows.firstObject;
- }
- }
- // If a window has not been returned by now, the first scene's window is returned (regardless of activationState).
- UIWindowScene *windowScene = (UIWindowScene *)[[UIApplication sharedApplication].connectedScenes allObjects].firstObject;
- return windowScene.windows.firstObject;
- } else {
-#if TARGET_OS_IOS
- return [[[UIApplication sharedApplication] delegate] window];
-#else
- return [UIApplication sharedApplication].keyWindow;
-#endif
- }
-}
-
-+ (NSBundle *)imageBundle {
-#if defined(SWIFTPM_MODULE_BUNDLE)
- NSBundle *bundle = SWIFTPM_MODULE_BUNDLE;
-#else
- NSBundle *bundle = [NSBundle bundleForClass:[SVProgressHUD class]];
-#endif
- NSURL *url = [bundle URLForResource:@"SVProgressHUD" withExtension:@"bundle"];
- return [NSBundle bundleWithURL:url];
- }
-
-#pragma mark - Setters
-
-+ (void)setStatus:(NSString*)status {
- [[self sharedView] setStatus:status];
-}
-
-+ (void)setDefaultStyle:(SVProgressHUDStyle)style {
- [self sharedView].defaultStyle = style;
-}
-
-+ (void)setDefaultMaskType:(SVProgressHUDMaskType)maskType {
- [self sharedView].defaultMaskType = maskType;
-}
-
-+ (void)setDefaultAnimationType:(SVProgressHUDAnimationType)type {
- [self sharedView].defaultAnimationType = type;
-}
-
-+ (void)setContainerView:(nullable UIView*)containerView {
- [self sharedView].containerView = containerView;
-}
-
-+ (void)setMinimumSize:(CGSize)minimumSize {
- [self sharedView].minimumSize = minimumSize;
-}
-
-+ (void)setRingThickness:(CGFloat)ringThickness {
- [self sharedView].ringThickness = ringThickness;
-}
-
-+ (void)setRingRadius:(CGFloat)radius {
- [self sharedView].ringRadius = radius;
-}
-
-+ (void)setRingNoTextRadius:(CGFloat)radius {
- [self sharedView].ringNoTextRadius = radius;
-}
-
-+ (void)setCornerRadius:(CGFloat)cornerRadius {
- [self sharedView].cornerRadius = cornerRadius;
-}
-
-+ (void)setBorderColor:(nonnull UIColor*)color {
- [self sharedView].hudView.layer.borderColor = color.CGColor;
-}
-
-+ (void)setBorderWidth:(CGFloat)width {
- [self sharedView].hudView.layer.borderWidth = width;
-}
-
-+ (void)setFont:(UIFont*)font {
- [self sharedView].font = font;
-}
-
-+ (void)setForegroundColor:(UIColor*)color {
- [self sharedView].foregroundColor = color;
- [self setDefaultStyle:SVProgressHUDStyleCustom];
-}
-
-+ (void)setForegroundImageColor:(UIColor *)color {
- [self sharedView].foregroundImageColor = color;
- [self setDefaultStyle:SVProgressHUDStyleCustom];
-}
-
-+ (void)setBackgroundColor:(UIColor*)color {
- [self sharedView].backgroundColor = color;
- [self setDefaultStyle:SVProgressHUDStyleCustom];
-}
-
-+ (void)setHudViewCustomBlurEffect:(UIBlurEffect*)blurEffect {
- [self sharedView].hudViewCustomBlurEffect = blurEffect;
- [self setDefaultStyle:SVProgressHUDStyleCustom];
-}
-
-+ (void)setBackgroundLayerColor:(UIColor*)color {
- [self sharedView].backgroundLayerColor = color;
-}
-
-+ (void)setImageViewSize:(CGSize)size {
- [self sharedView].imageViewSize = size;
-}
-
-+ (void)setShouldTintImages:(BOOL)shouldTintImages {
- [self sharedView].shouldTintImages = shouldTintImages;
-}
-
-+ (void)setInfoImage:(UIImage*)image {
- [self sharedView].infoImage = image;
-}
-
-+ (void)setSuccessImage:(UIImage*)image {
- [self sharedView].successImage = image;
-}
-
-+ (void)setErrorImage:(UIImage*)image {
- [self sharedView].errorImage = image;
-}
-
-+ (void)setViewForExtension:(UIView*)view {
- [self sharedView].viewForExtension = view;
-}
-
-+ (void)setGraceTimeInterval:(NSTimeInterval)interval {
- [self sharedView].graceTimeInterval = interval;
-}
-
-+ (void)setMinimumDismissTimeInterval:(NSTimeInterval)interval {
- [self sharedView].minimumDismissTimeInterval = interval;
-}
-
-+ (void)setMaximumDismissTimeInterval:(NSTimeInterval)interval {
- [self sharedView].maximumDismissTimeInterval = interval;
-}
-
-+ (void)setFadeInAnimationDuration:(NSTimeInterval)duration {
- [self sharedView].fadeInAnimationDuration = duration;
-}
-
-+ (void)setFadeOutAnimationDuration:(NSTimeInterval)duration {
- [self sharedView].fadeOutAnimationDuration = duration;
-}
-
-+ (void)setMaxSupportedWindowLevel:(UIWindowLevel)windowLevel {
- [self sharedView].maxSupportedWindowLevel = windowLevel;
-}
-
-+ (void)setHapticsEnabled:(BOOL)hapticsEnabled {
- [self sharedView].hapticsEnabled = hapticsEnabled;
-}
-
-+ (void)setMotionEffectEnabled:(BOOL)motionEffectEnabled {
- [self sharedView].motionEffectEnabled = motionEffectEnabled;
-}
-
-#pragma mark - Show Methods
-
-+ (void)show {
- [self showWithStatus:nil];
-}
-
-+ (void)showWithStatus:(NSString*)status {
- [self showProgress:SVProgressHUDUndefinedProgress status:status];
-}
-
-+ (void)showProgress:(float)progress {
- [self showProgress:progress status:nil];
-}
-
-+ (void)showProgress:(float)progress status:(NSString*)status {
- [[self sharedView] showProgress:progress status:status];
-}
-
-
-#pragma mark - Show, then automatically dismiss methods
-
-+ (void)showInfoWithStatus:(NSString*)status {
- [self showImage:[self sharedView].infoImage status:status];
-
-#if TARGET_OS_IOS
- dispatch_async(dispatch_get_main_queue(), ^{
- [[self sharedView].hapticGenerator notificationOccurred:UINotificationFeedbackTypeWarning];
- });
-#endif
-}
-
-+ (void)showSuccessWithStatus:(NSString*)status {
- [self showImage:[self sharedView].successImage status:status];
-
-#if TARGET_OS_IOS
- dispatch_async(dispatch_get_main_queue(), ^{
- [[self sharedView].hapticGenerator notificationOccurred:UINotificationFeedbackTypeSuccess];
- });
-#endif
-}
-
-+ (void)showErrorWithStatus:(NSString*)status {
- [self showImage:[self sharedView].errorImage status:status];
-
-#if TARGET_OS_IOS
- dispatch_async(dispatch_get_main_queue(), ^{
- [[self sharedView].hapticGenerator notificationOccurred:UINotificationFeedbackTypeError];
- });
-#endif
-}
-
-+ (void)showImage:(UIImage*)image status:(NSString*)status {
- NSTimeInterval displayInterval = [self displayDurationForString:status];
- [[self sharedView] showImage:image status:status duration:displayInterval];
-}
-
-
-#pragma mark - Dismiss Methods
-
-+ (void)popActivity {
- if([self sharedView].activityCount > 0) {
- [self sharedView].activityCount--;
- }
- if([self sharedView].activityCount == 0) {
- [[self sharedView] dismiss];
- }
-}
-
-+ (void)dismiss {
- [self dismissWithDelay:0.0 completion:nil];
-}
-
-+ (void)dismissWithCompletion:(SVProgressHUDDismissCompletion)completion {
- [self dismissWithDelay:0.0 completion:completion];
-}
-
-+ (void)dismissWithDelay:(NSTimeInterval)delay {
- [self dismissWithDelay:delay completion:nil];
-}
-
-+ (void)dismissWithDelay:(NSTimeInterval)delay completion:(SVProgressHUDDismissCompletion)completion {
- [[self sharedView] dismissWithDelay:delay completion:completion];
-}
-
-
-#pragma mark - Offset
-
-+ (void)setOffsetFromCenter:(UIOffset)offset {
- [self sharedView].offsetFromCenter = offset;
-}
-
-+ (void)resetOffsetFromCenter {
- [self setOffsetFromCenter:UIOffsetZero];
-}
-
-
-#pragma mark - Instance Methods
-
-- (instancetype)initWithFrame:(CGRect)frame {
- if((self = [super initWithFrame:frame])) {
- _isInitializing = YES;
-
- self.userInteractionEnabled = NO;
- self.activityCount = 0;
-
- self.backgroundView.alpha = 0.0f;
- self.imageView.alpha = 0.0f;
- self.statusLabel.alpha = 0.0f;
- self.indefiniteAnimatedView.alpha = 0.0f;
- self.ringView.alpha = self.backgroundRingView.alpha = 0.0f;
-
-
- _backgroundColor = [UIColor whiteColor];
- _foregroundColor = [UIColor blackColor];
- _backgroundLayerColor = [UIColor colorWithWhite:0 alpha:0.4];
-
- // Set default values
- _defaultMaskType = SVProgressHUDMaskTypeNone;
- _defaultStyle = SVProgressHUDStyleAutomatic;
- _defaultAnimationType = SVProgressHUDAnimationTypeFlat;
- _minimumSize = CGSizeZero;
- _font = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
-
- _imageViewSize = CGSizeMake(28.0f, 28.0f);
- _shouldTintImages = YES;
-
- NSBundle *imageBundle = [SVProgressHUD imageBundle];
-
- if (@available(iOS 13.0, *)) {
- _infoImage = [UIImage systemImageNamed:@"info.circle"];
- _successImage = [UIImage systemImageNamed:@"checkmark"];
- _errorImage = [UIImage systemImageNamed:@"xmark"];
- } else {
- _infoImage = [UIImage imageWithContentsOfFile:[imageBundle pathForResource:@"info" ofType:@"png"]];
- _successImage = [UIImage imageWithContentsOfFile:[imageBundle pathForResource:@"success" ofType:@"png"]];
- _errorImage = [UIImage imageWithContentsOfFile:[imageBundle pathForResource:@"error" ofType:@"png"]];
- }
-
- _ringThickness = 2.0f;
- _ringRadius = 18.0f;
- _ringNoTextRadius = 24.0f;
-
- _cornerRadius = 14.0f;
-
- _graceTimeInterval = 0.0f;
- _minimumDismissTimeInterval = 5.0;
- _maximumDismissTimeInterval = CGFLOAT_MAX;
-
- _fadeInAnimationDuration = SVProgressHUDDefaultAnimationDuration;
- _fadeOutAnimationDuration = SVProgressHUDDefaultAnimationDuration;
-
- _maxSupportedWindowLevel = UIWindowLevelNormal;
-
- _hapticsEnabled = NO;
- _motionEffectEnabled = YES;
-
- // Accessibility support
- self.accessibilityIdentifier = @"SVProgressHUD";
- self.isAccessibilityElement = YES;
-
- _isInitializing = NO;
- }
- return self;
-}
-
-- (void)updateHUDFrame {
- // Check if an image or progress ring is displayed
- BOOL imageUsed = (self.imageView.image) && !(self.imageView.hidden) && (self.imageViewSize.height > 0 && self.imageViewSize.width > 0);
- BOOL progressUsed = self.imageView.hidden;
-
- // Calculate size of string
- CGRect labelRect = CGRectZero;
- CGFloat labelHeight = 0.0f;
- CGFloat labelWidth = 0.0f;
-
- if(self.statusLabel.text) {
- CGSize constraintSize = CGSizeMake(200.0f, 300.0f);
- labelRect = [self.statusLabel.text boundingRectWithSize:constraintSize
- options:(NSStringDrawingOptions)(NSStringDrawingUsesFontLeading | NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin)
- attributes:@{NSFontAttributeName: self.statusLabel.font}
- context:NULL];
- labelHeight = ceilf(CGRectGetHeight(labelRect));
- labelWidth = ceilf(CGRectGetWidth(labelRect));
- }
-
- // Calculate hud size based on content
- // For the beginning use default values, these
- // might get update if string is too large etc.
- CGFloat hudWidth;
- CGFloat hudHeight;
-
- CGFloat contentWidth = 0.0f;
- CGFloat contentHeight = 0.0f;
-
- if(imageUsed || progressUsed) {
- contentWidth = CGRectGetWidth(imageUsed ? self.imageView.frame : self.indefiniteAnimatedView.frame);
- contentHeight = CGRectGetHeight(imageUsed ? self.imageView.frame : self.indefiniteAnimatedView.frame);
- }
-
- // |-spacing-content-spacing-|
- hudWidth = SVProgressHUDHorizontalSpacing + MAX(labelWidth, contentWidth) + SVProgressHUDHorizontalSpacing;
-
- // |-spacing-content-(labelSpacing-label-)spacing-|
- hudHeight = SVProgressHUDVerticalSpacing + labelHeight + contentHeight + SVProgressHUDVerticalSpacing;
- if(self.statusLabel.text && (imageUsed || progressUsed)){
- // Add spacing if both content and label are used
- hudHeight += SVProgressHUDLabelSpacing;
- }
-
- // Update values on subviews
- self.hudView.bounds = CGRectMake(0.0f, 0.0f, MAX(self.minimumSize.width, hudWidth), MAX(self.minimumSize.height, hudHeight));
-
- // Animate value update
- [CATransaction begin];
- [CATransaction setDisableActions:YES];
-
- // Spinner and image view
- CGFloat centerY;
- if(self.statusLabel.text) {
- CGFloat yOffset = MAX(SVProgressHUDVerticalSpacing, (self.minimumSize.height - contentHeight - SVProgressHUDLabelSpacing - labelHeight) / 2.0f);
- centerY = yOffset + contentHeight / 2.0f;
- } else {
- centerY = CGRectGetMidY(self.hudView.bounds);
- }
- self.indefiniteAnimatedView.center = CGPointMake(CGRectGetMidX(self.hudView.bounds), centerY);
- if(self.progress != SVProgressHUDUndefinedProgress) {
- self.backgroundRingView.center = self.ringView.center = CGPointMake(CGRectGetMidX(self.hudView.bounds), centerY);
- }
- self.imageView.center = CGPointMake(CGRectGetMidX(self.hudView.bounds), centerY);
-
- // Label
- if(imageUsed || progressUsed) {
- centerY = CGRectGetMaxY(imageUsed ? self.imageView.frame : self.indefiniteAnimatedView.frame) + SVProgressHUDLabelSpacing + labelHeight / 2.0f;
- } else {
- centerY = CGRectGetMidY(self.hudView.bounds);
- }
- self.statusLabel.frame = labelRect;
- self.statusLabel.center = CGPointMake(CGRectGetMidX(self.hudView.bounds), centerY);
-
- [CATransaction commit];
-}
-
-#if TARGET_OS_IOS
-- (void)updateMotionEffectForOrientation:(UIInterfaceOrientation)orientation {
- bool isPortrait = UIInterfaceOrientationIsPortrait(orientation);
- UIInterpolatingMotionEffectType xMotionEffectType = isPortrait ? UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis : UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis;
- UIInterpolatingMotionEffectType yMotionEffectType = isPortrait ? UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis : UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis;
- [self updateMotionEffectForXMotionEffectType:xMotionEffectType yMotionEffectType:yMotionEffectType];
-}
-#endif
-
-- (void)updateMotionEffectForXMotionEffectType:(UIInterpolatingMotionEffectType)xMotionEffectType yMotionEffectType:(UIInterpolatingMotionEffectType)yMotionEffectType {
- UIInterpolatingMotionEffect *effectX = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:xMotionEffectType];
- effectX.minimumRelativeValue = @(-SVProgressHUDParallaxDepthPoints);
- effectX.maximumRelativeValue = @(SVProgressHUDParallaxDepthPoints);
-
- UIInterpolatingMotionEffect *effectY = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:yMotionEffectType];
- effectY.minimumRelativeValue = @(-SVProgressHUDParallaxDepthPoints);
- effectY.maximumRelativeValue = @(SVProgressHUDParallaxDepthPoints);
-
- UIMotionEffectGroup *effectGroup = [UIMotionEffectGroup new];
- effectGroup.motionEffects = @[effectX, effectY];
-
- // Clear old motion effect, then add new motion effects
- self.hudView.motionEffects = @[];
- [self.hudView addMotionEffect:effectGroup];
-}
-
-- (void)updateViewHierarchy {
- // Add the overlay to the application window if necessary
- if(!self.controlView.superview) {
- if(self.containerView){
- [self.containerView addSubview:self.controlView];
- } else {
-#if !defined(SV_APP_EXTENSIONS)
- [self.frontWindow addSubview:self.controlView];
-#else
- // If SVProgressHUD is used inside an app extension add it to the given view
- if(self.viewForExtension) {
- [self.viewForExtension addSubview:self.controlView];
- }
-#endif
- }
- } else {
- // The HUD is already on screen, but maybe not in front. Therefore
- // ensure that overlay will be on top of rootViewController (which may
- // be changed during runtime).
- [self.controlView.superview bringSubviewToFront:self.controlView];
- }
-
- // Add self to the overlay view
- if(!self.superview) {
- [self.controlView addSubview:self];
- }
-}
-
-- (void)setStatus:(NSString*)status {
- self.statusLabel.text = status;
- self.statusLabel.hidden = status.length == 0;
- [self updateHUDFrame];
-}
-
-- (void)setGraceTimer:(NSTimer*)timer {
- if(_graceTimer) {
- [_graceTimer invalidate];
- _graceTimer = nil;
- }
- if(timer) {
- _graceTimer = timer;
- }
-}
-
-- (void)setFadeOutTimer:(NSTimer*)timer {
- if(_fadeOutTimer) {
- [_fadeOutTimer invalidate];
- _fadeOutTimer = nil;
- }
- if(timer) {
- _fadeOutTimer = timer;
- }
-}
-
-
-#pragma mark - Notifications and their handling
-
-- (void)registerNotifications {
-#if TARGET_OS_IOS
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(positionHUD:)
- name:UIApplicationDidChangeStatusBarOrientationNotification
- object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(positionHUD:)
- name:UIKeyboardWillHideNotification
- object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(positionHUD:)
- name:UIKeyboardDidHideNotification
- object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(positionHUD:)
- name:UIKeyboardWillShowNotification
- object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(positionHUD:)
- name:UIKeyboardDidShowNotification
- object:nil];
-#endif
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(positionHUD:)
- name:UIApplicationDidBecomeActiveNotification
- object:nil];
-}
-
-- (NSDictionary*)notificationUserInfo {
- return (self.statusLabel.text ? @{SVProgressHUDStatusUserInfoKey : self.statusLabel.text} : nil);
-}
-
-- (void)positionHUD:(NSNotification*)notification {
- CGFloat keyboardHeight = 0.0f;
- double animationDuration = 0.0;
-
-#if !defined(SV_APP_EXTENSIONS) && TARGET_OS_IOS
- self.frame = [SVProgressHUD mainWindow].bounds;
- UIInterfaceOrientation orientation = UIApplication.sharedApplication.statusBarOrientation;
-#elif !defined(SV_APP_EXTENSIONS) && !TARGET_OS_IOS
- self.frame = [SVProgressHUD mainWindow].bounds;
-#else
- if (self.viewForExtension) {
- self.frame = self.viewForExtension.frame;
- } else {
- self.frame = UIScreen.mainScreen.bounds;
- }
-#if TARGET_OS_IOS
- UIInterfaceOrientation orientation = CGRectGetWidth(self.frame) > CGRectGetHeight(self.frame) ? UIInterfaceOrientationLandscapeLeft : UIInterfaceOrientationPortrait;
-#endif
-#endif
-
-#if TARGET_OS_IOS
- // Get keyboardHeight in regard to current state
- if(notification) {
- NSDictionary* keyboardInfo = [notification userInfo];
- CGRect keyboardFrame = [keyboardInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue];
- animationDuration = [keyboardInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
-
- if(notification.name == UIKeyboardWillShowNotification || notification.name == UIKeyboardDidShowNotification) {
- keyboardHeight = CGRectGetWidth(keyboardFrame);
-
- if(UIInterfaceOrientationIsPortrait(orientation)) {
- keyboardHeight = CGRectGetHeight(keyboardFrame);
- }
- }
- } else {
- keyboardHeight = self.visibleKeyboardHeight;
- }
-#endif
-
- // Get the currently active frame of the display (depends on orientation)
- CGRect orientationFrame = self.bounds;
-
-#if !defined(SV_APP_EXTENSIONS) && TARGET_OS_IOS
- CGRect statusBarFrame = UIApplication.sharedApplication.statusBarFrame;
-#else
- CGRect statusBarFrame = CGRectZero;
-#endif
-
- if (_motionEffectEnabled) {
-#if TARGET_OS_IOS
- // Update the motion effects in regard to orientation
- [self updateMotionEffectForOrientation:orientation];
-#else
- [self updateMotionEffectForXMotionEffectType:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis yMotionEffectType:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
-#endif
- }
-
- // Calculate available height for display
- CGFloat activeHeight = CGRectGetHeight(orientationFrame);
- if(keyboardHeight > 0) {
- activeHeight += CGRectGetHeight(statusBarFrame) * 2;
- }
- activeHeight -= keyboardHeight;
-
- CGFloat posX = CGRectGetMidX(orientationFrame);
- CGFloat posY = floorf(activeHeight*0.45f);
-
- CGFloat rotateAngle = 0.0;
- CGPoint newCenter = CGPointMake(posX, posY);
-
- if(notification) {
- // Animate update if notification was present
- [UIView animateWithDuration:animationDuration
- delay:0
- options:(UIViewAnimationOptions) (UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState)
- animations:^{
- [self moveToPoint:newCenter rotateAngle:rotateAngle];
- [self.hudView setNeedsDisplay];
- } completion:nil];
- } else {
- [self moveToPoint:newCenter rotateAngle:rotateAngle];
- }
-}
-
-- (void)moveToPoint:(CGPoint)newCenter rotateAngle:(CGFloat)angle {
- self.hudView.transform = CGAffineTransformMakeRotation(angle);
- if (self.containerView) {
- self.hudView.center = CGPointMake(self.containerView.center.x + self.offsetFromCenter.horizontal, self.containerView.center.y + self.offsetFromCenter.vertical);
- } else {
- self.hudView.center = CGPointMake(newCenter.x + self.offsetFromCenter.horizontal, newCenter.y + self.offsetFromCenter.vertical);
- }
-}
-
-
-#pragma mark - Event handling
-
-- (void)controlViewDidReceiveTouchEvent:(id)sender forEvent:(UIEvent*)event {
- [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidReceiveTouchEventNotification
- object:self
- userInfo:[self notificationUserInfo]];
-
- UITouch *touch = event.allTouches.anyObject;
- CGPoint touchLocation = [touch locationInView:self];
-
- if(CGRectContainsPoint(self.hudView.frame, touchLocation)) {
- [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidTouchDownInsideNotification
- object:self
- userInfo:[self notificationUserInfo]];
- }
-}
-
-
-#pragma mark - Master show/dismiss methods
-
-- (void)showProgress:(float)progress status:(NSString*)status {
- __weak SVProgressHUD *weakSelf = self;
- [[NSOperationQueue mainQueue] addOperationWithBlock:^{
- __strong SVProgressHUD *strongSelf = weakSelf;
- if(strongSelf){
- if(strongSelf.fadeOutTimer) {
- strongSelf.activityCount = 0;
- }
-
- // Stop timer
- strongSelf.fadeOutTimer = nil;
- strongSelf.graceTimer = nil;
-
- // Update / Check view hierarchy to ensure the HUD is visible
- [strongSelf updateViewHierarchy];
-
- // Reset imageView and fadeout timer if an image is currently displayed
- strongSelf.imageView.hidden = YES;
- strongSelf.imageView.image = nil;
-
- // Update text and set progress to the given value
- strongSelf.statusLabel.hidden = status.length == 0;
- strongSelf.statusLabel.text = status;
- strongSelf.progress = progress;
-
- // Choose the "right" indicator depending on the progress
- if(progress >= 0) {
- // Cancel the indefiniteAnimatedView, then show the ringLayer
- [strongSelf cancelIndefiniteAnimatedViewAnimation];
-
- // Add ring to HUD
- if(!strongSelf.ringView.superview){
- [strongSelf.hudView.contentView addSubview:strongSelf.ringView];
- }
- if(!strongSelf.backgroundRingView.superview){
- [strongSelf.hudView.contentView addSubview:strongSelf.backgroundRingView];
- }
-
- // Set progress animated
- [CATransaction begin];
- [CATransaction setDisableActions:YES];
- strongSelf.ringView.strokeEnd = progress;
- [CATransaction commit];
-
- // Update the activity count
- if(progress == 0) {
- strongSelf.activityCount++;
- }
- } else {
- // Cancel the ringLayer animation, then show the indefiniteAnimatedView
- [strongSelf cancelRingLayerAnimation];
-
- // Add indefiniteAnimatedView to HUD
- [strongSelf.hudView.contentView addSubview:strongSelf.indefiniteAnimatedView];
- if([strongSelf.indefiniteAnimatedView respondsToSelector:@selector(startAnimating)]) {
- [(id)strongSelf.indefiniteAnimatedView startAnimating];
- }
-
- // Update the activity count
- strongSelf.activityCount++;
- }
-
- // Fade in delayed if a grace time is set
- if (self.graceTimeInterval > 0.0 && self.backgroundView.alpha == 0.0f) {
- strongSelf.graceTimer = [NSTimer timerWithTimeInterval:self.graceTimeInterval target:strongSelf selector:@selector(fadeIn:) userInfo:nil repeats:NO];
- [[NSRunLoop mainRunLoop] addTimer:strongSelf.graceTimer forMode:NSRunLoopCommonModes];
- } else {
- [strongSelf fadeIn:nil];
- }
-
- // Tell the Haptics Generator to prepare for feedback, which may come soon
-#if TARGET_OS_IOS
- [strongSelf.hapticGenerator prepare];
-#endif
- }
- }];
-}
-
-- (void)showImage:(UIImage*)image status:(NSString*)status duration:(NSTimeInterval)duration {
- __weak SVProgressHUD *weakSelf = self;
- [[NSOperationQueue mainQueue] addOperationWithBlock:^{
- __strong SVProgressHUD *strongSelf = weakSelf;
- if(strongSelf){
- // Stop timer
- strongSelf.fadeOutTimer = nil;
- strongSelf.graceTimer = nil;
-
- // Update / Check view hierarchy to ensure the HUD is visible
- [strongSelf updateViewHierarchy];
-
- // Reset progress and cancel any running animation
- strongSelf.progress = SVProgressHUDUndefinedProgress;
- [strongSelf cancelRingLayerAnimation];
- [strongSelf cancelIndefiniteAnimatedViewAnimation];
-
- // Update imageView
- if (self.shouldTintImages) {
- if (image.renderingMode != UIImageRenderingModeAlwaysTemplate) {
- strongSelf.imageView.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
- } else {
- strongSelf.imageView.image = image;
- }
- strongSelf.imageView.tintColor = strongSelf.foregroundImageColorForStyle;
- } else {
- strongSelf.imageView.image = image;
- }
- strongSelf.imageView.hidden = NO;
-
- // Update text
- strongSelf.statusLabel.hidden = status.length == 0;
- strongSelf.statusLabel.text = status;
-
- // Fade in delayed if a grace time is set
- // An image will be dismissed automatically. Thus pass the duration as userInfo.
- if (self.graceTimeInterval > 0.0 && self.backgroundView.alpha == 0.0f) {
- strongSelf.graceTimer = [NSTimer timerWithTimeInterval:self.graceTimeInterval target:strongSelf selector:@selector(fadeIn:) userInfo:@(duration) repeats:NO];
- [[NSRunLoop mainRunLoop] addTimer:strongSelf.graceTimer forMode:NSRunLoopCommonModes];
- } else {
- [strongSelf fadeIn:@(duration)];
- }
- }
- }];
-}
-
-- (void)fadeIn:(id)data {
- // Update the HUDs frame to the new content and position HUD
- [self updateHUDFrame];
- [self positionHUD:nil];
-
- // Update accessibility as well as user interaction
- // \n cause to read text twice so remove "\n" new line character before setting up accessiblity label
- NSString *accessibilityString = [[self.statusLabel.text componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]] componentsJoinedByString:@" "];
- if(self.defaultMaskType != SVProgressHUDMaskTypeNone) {
- self.controlView.userInteractionEnabled = YES;
- self.accessibilityLabel = accessibilityString ?: NSLocalizedString(@"Loading", nil);
- self.isAccessibilityElement = YES;
- self.controlView.accessibilityViewIsModal = YES;
- } else {
- self.controlView.userInteractionEnabled = NO;
- self.hudView.accessibilityLabel = accessibilityString ?: NSLocalizedString(@"Loading", nil);
- self.isAccessibilityElement = NO;
- self.hudView.isAccessibilityElement = YES;
- self.controlView.accessibilityViewIsModal = NO;
- }
-
- // Get duration
- id duration = [data isKindOfClass:[NSTimer class]] ? ((NSTimer *)data).userInfo : data;
-
- // Show if not already visible
- if(self.backgroundView.alpha != 1.0f) {
- // Post notification to inform user
- [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDWillAppearNotification
- object:self
- userInfo:[self notificationUserInfo]];
-
- // Zoom HUD a little to to make a nice appear / pop up animation
- self.hudView.transform = self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 1.3f, 1.3f);
-
- __block void (^animationsBlock)(void) = ^{
- // Zoom HUD a little to make a nice appear / pop up animation
- self.hudView.transform = CGAffineTransformIdentity;
-
- // Fade in all effects (colors, blur, etc.)
- [self fadeInEffects];
- };
-
- __block void (^completionBlock)(void) = ^{
- // Check if we really achieved to show the HUD (<=> alpha)
- // and the change of these values has not been cancelled in between e.g. due to a dismissal
- if(self.backgroundView.alpha == 1.0f){
- // Register observer <=> we now have to handle orientation changes etc.
- [self registerNotifications];
-
- // Post notification to inform user
- [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidAppearNotification
- object:self
- userInfo:[self notificationUserInfo]];
-
- // Update accessibility
- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
- UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, self.statusLabel.text);
-
- // Dismiss automatically if a duration was passed as userInfo. We start a timer
- // which then will call dismiss after the predefined duration
- if(duration){
- self.fadeOutTimer = [NSTimer timerWithTimeInterval:[(NSNumber *)duration doubleValue] target:self selector:@selector(dismiss) userInfo:nil repeats:NO];
- [[NSRunLoop mainRunLoop] addTimer:self.fadeOutTimer forMode:NSRunLoopCommonModes];
- }
- }
- };
-
- // Animate appearance
- if (self.fadeInAnimationDuration > 0) {
- // Animate appearance
- [UIView animateWithDuration:self.fadeInAnimationDuration
- delay:0
- options:(UIViewAnimationOptions) (UIViewAnimationOptionAllowUserInteraction | UIViewAnimationCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState)
- animations:^{
- animationsBlock();
- } completion:^(BOOL finished) {
- completionBlock();
- }];
- } else {
- animationsBlock();
- completionBlock();
- }
-
- // Inform iOS to redraw the view hierarchy
- [self setNeedsDisplay];
- } else {
- // Update accessibility
- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
- UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, self.statusLabel.text);
-
- // Dismiss automatically if a duration was passed as userInfo. We start a timer
- // which then will call dismiss after the predefined duration
- if(duration){
- self.fadeOutTimer = [NSTimer timerWithTimeInterval:[(NSNumber *)duration doubleValue] target:self selector:@selector(dismiss) userInfo:nil repeats:NO];
- [[NSRunLoop mainRunLoop] addTimer:self.fadeOutTimer forMode:NSRunLoopCommonModes];
- }
- }
-}
-
-- (void)dismiss {
- [self dismissWithDelay:0.0 completion:nil];
-}
-
-- (void)dismissWithDelay:(NSTimeInterval)delay completion:(SVProgressHUDDismissCompletion)completion {
- __weak SVProgressHUD *weakSelf = self;
- [[NSOperationQueue mainQueue] addOperationWithBlock:^{
- __strong SVProgressHUD *strongSelf = weakSelf;
- if(strongSelf){
-
- // Post notification to inform user
- [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDWillDisappearNotification
- object:nil
- userInfo:[strongSelf notificationUserInfo]];
-
- // Reset activity count
- strongSelf.activityCount = 0;
-
- __block void (^animationsBlock)(void) = ^{
- // Shrink HUD a little to make a nice disappear animation
- strongSelf.hudView.transform = CGAffineTransformScale(strongSelf.hudView.transform, 1/1.3f, 1/1.3f);
-
- // Fade out all effects (colors, blur, etc.)
- [strongSelf fadeOutEffects];
- };
-
- __block void (^completionBlock)(void) = ^{
- // Check if we really achieved to dismiss the HUD (<=> alpha values are applied)
- // and the change of these values has not been cancelled in between e.g. due to a new show
- if(self.backgroundView.alpha == 0.0f){
- // Clean up view hierarchy (overlays)
- [strongSelf.controlView removeFromSuperview];
- [strongSelf.backgroundView removeFromSuperview];
- [strongSelf.hudView removeFromSuperview];
- [strongSelf removeFromSuperview];
-
- // Reset progress and cancel any running animation
- strongSelf.progress = SVProgressHUDUndefinedProgress;
- [strongSelf cancelRingLayerAnimation];
- [strongSelf cancelIndefiniteAnimatedViewAnimation];
-
- // Remove observer <=> we do not have to handle orientation changes etc.
- [[NSNotificationCenter defaultCenter] removeObserver:strongSelf];
-
- // Post notification to inform user
- [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidDisappearNotification
- object:strongSelf
- userInfo:[strongSelf notificationUserInfo]];
-
- // Tell the rootViewController to update the StatusBar appearance
-#if !defined(SV_APP_EXTENSIONS) && TARGET_OS_IOS
- UIViewController *rootController = [SVProgressHUD mainWindow].rootViewController;
- [rootController setNeedsStatusBarAppearanceUpdate];
-#endif
-
- // Run an (optional) completionHandler
- if (completion) {
- completion();
- }
- }
- };
-
- // UIViewAnimationOptionBeginFromCurrentState AND a delay doesn't always work as expected
- // When UIViewAnimationOptionBeginFromCurrentState is set, animateWithDuration: evaluates the current
- // values to check if an animation is necessary. The evaluation happens at function call time and not
- // after the delay => the animation is sometimes skipped. Therefore we delay using dispatch_after.
-
- dispatch_time_t dipatchTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC));
- dispatch_after(dipatchTime, dispatch_get_main_queue(), ^{
-
- // Stop timer
- strongSelf.graceTimer = nil;
-
- if (strongSelf.fadeOutAnimationDuration > 0) {
- // Animate appearance
- [UIView animateWithDuration:strongSelf.fadeOutAnimationDuration
- delay:0
- options:(UIViewAnimationOptions) (UIViewAnimationOptionAllowUserInteraction | UIViewAnimationCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState)
- animations:^{
- animationsBlock();
- } completion:^(BOOL finished) {
- completionBlock();
- }];
- } else {
- animationsBlock();
- completionBlock();
- }
- });
-
- // Inform iOS to redraw the view hierarchy
- [strongSelf setNeedsDisplay];
- }
- }];
-}
-
-
-#pragma mark - Ring progress animation
-
-- (UIView*)indefiniteAnimatedView {
- // Get the correct spinner for defaultAnimationType
- if(self.defaultAnimationType == SVProgressHUDAnimationTypeFlat){
- // Check if spinner exists and is an object of different class
- if(_indefiniteAnimatedView && ![_indefiniteAnimatedView isKindOfClass:[SVIndefiniteAnimatedView class]]){
- [_indefiniteAnimatedView removeFromSuperview];
- _indefiniteAnimatedView = nil;
- }
-
- if(!_indefiniteAnimatedView){
- _indefiniteAnimatedView = [[SVIndefiniteAnimatedView alloc] initWithFrame:CGRectZero];
- }
-
- // Update styling
- SVIndefiniteAnimatedView *indefiniteAnimatedView = (SVIndefiniteAnimatedView*)_indefiniteAnimatedView;
- indefiniteAnimatedView.strokeColor = self.foregroundImageColorForStyle;
- indefiniteAnimatedView.strokeThickness = self.ringThickness;
- indefiniteAnimatedView.radius = self.statusLabel.text ? self.ringRadius : self.ringNoTextRadius;
- } else {
- // Check if spinner exists and is an object of different class
- if(_indefiniteAnimatedView && ![_indefiniteAnimatedView isKindOfClass:[UIActivityIndicatorView class]]){
- [_indefiniteAnimatedView removeFromSuperview];
- _indefiniteAnimatedView = nil;
- }
-
- if(!_indefiniteAnimatedView){
- _indefiniteAnimatedView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
- }
-
- // Update styling
- UIActivityIndicatorView *activityIndicatorView = (UIActivityIndicatorView*)_indefiniteAnimatedView;
- activityIndicatorView.color = self.foregroundImageColorForStyle;
- }
- [_indefiniteAnimatedView sizeToFit];
-
- return _indefiniteAnimatedView;
-}
-
-- (SVProgressAnimatedView*)ringView {
- if(!_ringView) {
- _ringView = [[SVProgressAnimatedView alloc] initWithFrame:CGRectZero];
- }
-
- // Update styling
- _ringView.strokeColor = self.foregroundImageColorForStyle;
- _ringView.strokeThickness = self.ringThickness;
- _ringView.radius = self.statusLabel.text ? self.ringRadius : self.ringNoTextRadius;
-
- return _ringView;
-}
-
-- (SVProgressAnimatedView*)backgroundRingView {
- if(!_backgroundRingView) {
- _backgroundRingView = [[SVProgressAnimatedView alloc] initWithFrame:CGRectZero];
- _backgroundRingView.strokeEnd = 1.0f;
- }
-
- // Update styling
- _backgroundRingView.strokeColor = [self.foregroundImageColorForStyle colorWithAlphaComponent:0.1f];
- _backgroundRingView.strokeThickness = self.ringThickness;
- _backgroundRingView.radius = self.statusLabel.text ? self.ringRadius : self.ringNoTextRadius;
-
- return _backgroundRingView;
-}
-
-- (void)cancelRingLayerAnimation {
- // Animate value update, stop animation
- [CATransaction begin];
- [CATransaction setDisableActions:YES];
-
- [self.hudView.layer removeAllAnimations];
- self.ringView.strokeEnd = 0.0f;
-
- [CATransaction commit];
-
- // Remove from view
- [self.ringView removeFromSuperview];
- [self.backgroundRingView removeFromSuperview];
-}
-
-- (void)cancelIndefiniteAnimatedViewAnimation {
- // Stop animation
- if([self.indefiniteAnimatedView respondsToSelector:@selector(stopAnimating)]) {
- [(id)self.indefiniteAnimatedView stopAnimating];
- }
- // Remove from view
- [self.indefiniteAnimatedView removeFromSuperview];
-}
-
-
-#pragma mark - Utilities
-
-+ (BOOL)isVisible {
- // Checking one alpha value is sufficient as they are all the same
- return [self sharedView].backgroundView.alpha > 0.0f;
-}
-
-
-#pragma mark - Getters
-
-+ (NSTimeInterval)displayDurationForString:(NSString*)string {
- CGFloat minimum = MAX((CGFloat)string.length * 0.06 + 0.5, [self sharedView].minimumDismissTimeInterval);
- return MIN(minimum, [self sharedView].maximumDismissTimeInterval);
-}
-
-- (UIColor*)foregroundColorForStyle {
- SVProgressHUDStyle style = [self defaultStyleResolvingAutomatic];
-
- if(style == SVProgressHUDStyleLight) {
- return [UIColor blackColor];
- } else if(style == SVProgressHUDStyleDark) {
- return [UIColor whiteColor];
- } else {
- return self.foregroundColor;
- }
-}
-
-- (UIColor*)foregroundImageColorForStyle {
- if (self.foregroundImageColor) {
- return self.foregroundImageColor;
- } else {
- return [self foregroundColorForStyle];
- }
-}
-
-- (UIColor*)backgroundColorForStyle {
- SVProgressHUDStyle style = [self defaultStyleResolvingAutomatic];
-
- if(style == SVProgressHUDStyleLight) {
- return [UIColor whiteColor];
- } else if(style == SVProgressHUDStyleDark) {
- return [UIColor blackColor];
- } else {
- return self.backgroundColor;
- }
-}
-
-- (UIControl*)controlView {
- if(!_controlView) {
- _controlView = [UIControl new];
- _controlView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- _controlView.backgroundColor = [UIColor clearColor];
- _controlView.userInteractionEnabled = YES;
- [_controlView addTarget:self action:@selector(controlViewDidReceiveTouchEvent:forEvent:) forControlEvents:UIControlEventTouchDown];
- }
-
- // Update frame
-#if !defined(SV_APP_EXTENSIONS)
- _controlView.frame = [SVProgressHUD mainWindow].bounds;
-#else
- _controlView.frame = [UIScreen mainScreen].bounds;
-#endif
-
- return _controlView;
-}
-
--(UIView *)backgroundView {
- if(!_backgroundView){
- _backgroundView = [UIView new];
- _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- }
- if(!_backgroundView.superview){
- [self insertSubview:_backgroundView belowSubview:self.hudView];
- }
-
- // Update styling
- if(self.defaultMaskType == SVProgressHUDMaskTypeGradient){
- if(!_backgroundRadialGradientLayer){
- _backgroundRadialGradientLayer = [SVRadialGradientLayer layer];
- }
- if(!_backgroundRadialGradientLayer.superlayer){
- [_backgroundView.layer insertSublayer:_backgroundRadialGradientLayer atIndex:0];
- }
- _backgroundView.backgroundColor = [UIColor clearColor];
- } else {
- if(_backgroundRadialGradientLayer && _backgroundRadialGradientLayer.superlayer){
- [_backgroundRadialGradientLayer removeFromSuperlayer];
- }
- if(self.defaultMaskType == SVProgressHUDMaskTypeBlack){
- _backgroundView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.4];
- } else if(self.defaultMaskType == SVProgressHUDMaskTypeCustom){
- _backgroundView.backgroundColor = self.backgroundLayerColor;
- } else {
- _backgroundView.backgroundColor = [UIColor clearColor];
- }
- }
-
- // Update frame
- if(_backgroundView){
- _backgroundView.frame = self.bounds;
- }
- if(_backgroundRadialGradientLayer){
- _backgroundRadialGradientLayer.frame = self.bounds;
-
- // Calculate the new center of the gradient, it may change if keyboard is visible
- CGPoint gradientCenter = self.center;
- gradientCenter.y = (self.bounds.size.height - self.visibleKeyboardHeight)/2;
- _backgroundRadialGradientLayer.gradientCenter = gradientCenter;
- [_backgroundRadialGradientLayer setNeedsDisplay];
- }
-
- return _backgroundView;
-}
-- (UIVisualEffectView*)hudView {
- if(!_hudView) {
- _hudView = [UIVisualEffectView new];
- _hudView.layer.masksToBounds = YES;
- _hudView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
- }
- if(!_hudView.superview) {
- [self addSubview:_hudView];
- }
-
- // Update styling
- _hudView.layer.cornerRadius = self.cornerRadius;
-
- return _hudView;
-}
-
-- (UILabel*)statusLabel {
- if(!_statusLabel) {
- _statusLabel = [[UILabel alloc] initWithFrame:CGRectZero];
- _statusLabel.backgroundColor = [UIColor clearColor];
- _statusLabel.adjustsFontSizeToFitWidth = YES;
- _statusLabel.adjustsFontForContentSizeCategory = YES;
- _statusLabel.textAlignment = NSTextAlignmentCenter;
- _statusLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
- _statusLabel.numberOfLines = 0;
- }
- if(!_statusLabel.superview) {
- [self.hudView.contentView addSubview:_statusLabel];
- }
-
- // Update styling
- _statusLabel.textColor = self.foregroundColorForStyle;
- _statusLabel.font = self.font;
-
- return _statusLabel;
-}
-
-- (UIImageView*)imageView {
- if(_imageView && !CGSizeEqualToSize(_imageView.bounds.size, _imageViewSize)) {
- [_imageView removeFromSuperview];
- _imageView = nil;
- }
-
- if(!_imageView) {
- _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, _imageViewSize.width, _imageViewSize.height)];
- }
- if(!_imageView.superview) {
- [self.hudView.contentView addSubview:_imageView];
- }
-
- return _imageView;
-}
-
-
-#pragma mark - Helper
-
-- (SVProgressHUDStyle) defaultStyleResolvingAutomatic {
- if(self.defaultStyle == SVProgressHUDStyleAutomatic) {
- return self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark ? SVProgressHUDStyleDark : SVProgressHUDStyleLight;
- }
-
- return self.defaultStyle;
-}
-
-- (CGFloat)visibleKeyboardHeight {
-#if !defined(SV_APP_EXTENSIONS)
- UIWindow *keyboardWindow = nil;
- for (UIWindow *testWindow in UIApplication.sharedApplication.windows) {
- if(![testWindow.class isEqual:UIWindow.class]) {
- keyboardWindow = testWindow;
- break;
- }
- }
-
- for (__strong UIView *possibleKeyboard in keyboardWindow.subviews) {
- NSString *viewName = NSStringFromClass(possibleKeyboard.class);
- if([viewName hasPrefix:@"UI"]){
- if([viewName hasSuffix:@"PeripheralHostView"] || [viewName hasSuffix:@"Keyboard"]){
- return CGRectGetHeight(possibleKeyboard.bounds);
- } else if ([viewName hasSuffix:@"InputSetContainerView"]){
- for (__strong UIView *possibleKeyboardSubview in possibleKeyboard.subviews) {
- viewName = NSStringFromClass(possibleKeyboardSubview.class);
- if([viewName hasPrefix:@"UI"] && [viewName hasSuffix:@"InputSetHostView"]) {
- CGRect convertedRect = [possibleKeyboard convertRect:possibleKeyboardSubview.frame toView:self];
- CGRect intersectedRect = CGRectIntersection(convertedRect, self.bounds);
- if (!CGRectIsNull(intersectedRect)) {
- return CGRectGetHeight(intersectedRect);
- }
- }
- }
- }
- }
- }
-#endif
- return 0;
-}
-
-- (UIWindow *)frontWindow {
-#if !defined(SV_APP_EXTENSIONS)
- NSEnumerator *frontToBackWindows = [UIApplication.sharedApplication.windows reverseObjectEnumerator];
- for (UIWindow *window in frontToBackWindows) {
- BOOL windowOnMainScreen = window.screen == UIScreen.mainScreen;
- BOOL windowIsVisible = !window.hidden && window.alpha > 0;
- BOOL windowLevelSupported = (window.windowLevel >= UIWindowLevelNormal && window.windowLevel <= self.maxSupportedWindowLevel);
- BOOL windowKeyWindow = window.isKeyWindow;
-
- if(windowOnMainScreen && windowIsVisible && windowLevelSupported && windowKeyWindow) {
- return window;
- }
- }
-#endif
- return nil;
-}
-
-- (void)fadeInEffects {
- if(self.defaultStyle != SVProgressHUDStyleCustom) {
- // Add blur effect
- UIBlurEffectStyle blurEffectStyle;
-#if TARGET_OS_IOS
- if (@available(iOS 13.0, *)) {
- blurEffectStyle = [self defaultStyleResolvingAutomatic] == SVProgressHUDStyleLight ? UIBlurEffectStyleSystemMaterial : UIBlurEffectStyleSystemMaterialDark;
- } else {
- blurEffectStyle = [self defaultStyleResolvingAutomatic] == SVProgressHUDStyleLight ? UIBlurEffectStyleLight : UIBlurEffectStyleDark;
- }
-#else
- blurEffectStyle = [self defaultStyleResolvingAutomatic] == SVProgressHUDStyleLight ? UIBlurEffectStyleLight : UIBlurEffectStyleDark;
-#endif
-
- UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:blurEffectStyle];
- self.hudView.effect = blurEffect;
-
- // We omit UIVibrancy effect and use a suitable background color as an alternative.
- // This will make everything more readable. See the following for details:
- // https://www.omnigroup.com/developer/how-to-make-text-in-a-uivisualeffectview-readable-on-any-background
-
- self.hudView.backgroundColor = [self.backgroundColorForStyle colorWithAlphaComponent:0.6f];
- } else {
- self.hudView.effect = self.hudViewCustomBlurEffect;
- self.hudView.backgroundColor = self.backgroundColorForStyle;
- }
-
- // Fade in views
- self.backgroundView.alpha = 1.0f;
-
- self.imageView.alpha = 1.0f;
- self.statusLabel.alpha = 1.0f;
- self.indefiniteAnimatedView.alpha = 1.0f;
- self.ringView.alpha = self.backgroundRingView.alpha = 1.0f;
-}
-
-- (void)fadeOutEffects
-{
- if(self.defaultStyle != SVProgressHUDStyleCustom) {
- // Remove blur effect
- self.hudView.effect = nil;
- }
-
- // Remove background color
- self.hudView.backgroundColor = [UIColor clearColor];
-
- // Fade out views
- self.backgroundView.alpha = 0.0f;
-
- self.imageView.alpha = 0.0f;
- self.statusLabel.alpha = 0.0f;
- self.indefiniteAnimatedView.alpha = 0.0f;
- self.ringView.alpha = self.backgroundRingView.alpha = 0.0f;
-}
-
-#if TARGET_OS_IOS
-- (UINotificationFeedbackGenerator *)hapticGenerator {
- // Only return if haptics are enabled
- if(!self.hapticsEnabled) {
- return nil;
- }
-
- if(!_hapticGenerator) {
- _hapticGenerator = [[UINotificationFeedbackGenerator alloc] init];
- }
- return _hapticGenerator;
-}
-#endif
-
-
-#pragma mark - UIAppearance Setters
-
-- (void)setDefaultStyle:(SVProgressHUDStyle)style {
- if (!_isInitializing) _defaultStyle = style;
-}
-
-- (void)setDefaultMaskType:(SVProgressHUDMaskType)maskType {
- if (!_isInitializing) _defaultMaskType = maskType;
-}
-
-- (void)setDefaultAnimationType:(SVProgressHUDAnimationType)animationType {
- if (!_isInitializing) _defaultAnimationType = animationType;
-}
-
-- (void)setContainerView:(UIView *)containerView {
- if (!_isInitializing) _containerView = containerView;
-}
-
-- (void)setMinimumSize:(CGSize)minimumSize {
- if (!_isInitializing) _minimumSize = minimumSize;
-}
-
-- (void)setRingThickness:(CGFloat)ringThickness {
- if (!_isInitializing) _ringThickness = ringThickness;
-}
-
-- (void)setRingRadius:(CGFloat)ringRadius {
- if (!_isInitializing) _ringRadius = ringRadius;
-}
-
-- (void)setRingNoTextRadius:(CGFloat)ringNoTextRadius {
- if (!_isInitializing) _ringNoTextRadius = ringNoTextRadius;
-}
-
-- (void)setCornerRadius:(CGFloat)cornerRadius {
- if (!_isInitializing) _cornerRadius = cornerRadius;
-}
-
-- (void)setFont:(UIFont*)font {
- if (!_isInitializing) _font = font;
-}
-
-- (void)setForegroundColor:(UIColor*)color {
- if (!_isInitializing) _foregroundColor = color;
-}
-
-- (void)setForegroundImageColor:(UIColor *)color {
- if (!_isInitializing) _foregroundImageColor = color;
-}
-
-- (void)setBackgroundColor:(UIColor*)color {
- if (!_isInitializing) _backgroundColor = color;
-}
-
-- (void)setBackgroundLayerColor:(UIColor*)color {
- if (!_isInitializing) _backgroundLayerColor = color;
-}
-
-- (void)setShouldTintImages:(BOOL)shouldTintImages {
- if (!_isInitializing) _shouldTintImages = shouldTintImages;
-}
-
-- (void)setInfoImage:(UIImage*)image {
- if (!_isInitializing) _infoImage = image;
-}
-
-- (void)setSuccessImage:(UIImage*)image {
- if (!_isInitializing) _successImage = image;
-}
-
-- (void)setErrorImage:(UIImage*)image {
- if (!_isInitializing) _errorImage = image;
-}
-
-- (void)setViewForExtension:(UIView*)view {
- if (!_isInitializing) _viewForExtension = view;
-}
-
-- (void)setOffsetFromCenter:(UIOffset)offset {
- if (!_isInitializing) _offsetFromCenter = offset;
-}
-
-- (void)setMinimumDismissTimeInterval:(NSTimeInterval)minimumDismissTimeInterval {
- if (!_isInitializing) _minimumDismissTimeInterval = minimumDismissTimeInterval;
-}
-
-- (void)setFadeInAnimationDuration:(NSTimeInterval)duration {
- if (!_isInitializing) _fadeInAnimationDuration = duration;
-}
-
-- (void)setFadeOutAnimationDuration:(NSTimeInterval)duration {
- if (!_isInitializing) _fadeOutAnimationDuration = duration;
-}
-
-- (void)setMaxSupportedWindowLevel:(UIWindowLevel)maxSupportedWindowLevel {
- if (!_isInitializing) _maxSupportedWindowLevel = maxSupportedWindowLevel;
-}
-
-@end
+++ /dev/null
-//
-// SVRadialGradientLayer.h
-// SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
-//
-// Copyright (c) 2014-2023 Tobias Totzek and contributors. All rights reserved.
-//
-
-#import <QuartzCore/QuartzCore.h>
-
-@interface SVRadialGradientLayer : CALayer
-
-@property (nonatomic) CGPoint gradientCenter;
-
-@end
+++ /dev/null
-//
-// SVRadialGradientLayer.m
-// SVProgressHUD, https://github.com/SVProgressHUD/SVProgressHUD
-//
-// Copyright (c) 2014-2023 Tobias Totzek and contributors. All rights reserved.
-//
-
-#import "SVRadialGradientLayer.h"
-
-@implementation SVRadialGradientLayer
-
-- (void)drawInContext:(CGContextRef)context {
- size_t locationsCount = 2;
- CGFloat locations[2] = {0.0f, 1.0f};
- CGFloat colors[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.75f};
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, locations, locationsCount);
- CGColorSpaceRelease(colorSpace);
-
- float radius = MIN(self.bounds.size.width , self.bounds.size.height);
- CGContextDrawRadialGradient (context, gradient, self.gradientCenter, 0, self.gradientCenter, radius, kCGGradientDrawsAfterEndLocation);
- CGGradientRelease(gradient);
-}
-
-@end
+++ /dev/null
-Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+++ /dev/null
-<img src="https://snapkit.github.io/SnapKit/images/banner.jpg" alt="" />
-
-SnapKit is a DSL to make Auto Layout easy on both iOS and OS X.
-
-[](https://travis-ci.org/SnapKit/SnapKit)
-[](https://github.com/SnapKit/SnapKit)
-[](https://cocoapods.org/pods/SnapKit)
-[](https://github.com/Carthage/Carthage)
-
-#### ⚠️ **To use with Swift 4.x please ensure you are using >= 4.0.0** ⚠️
-#### ⚠️ **To use with Swift 5.x please ensure you are using >= 5.0.0** ⚠️
-
-## Contents
-
-- [Requirements](#requirements)
-- [Migration Guides](#migration-guides)
-- [Communication](#communication)
-- [Installation](#installation)
-- [Usage](#usage)
-- [Credits](#credits)
-- [License](#license)
-
-## Requirements
-
-- iOS 12.0+ / Mac OS X 10.13+ / tvOS 10.0+
-- Xcode 10.0+
-- Swift 4.0+
-
-## Migration Guides
-
-- [SnapKit 3.0 Migration Guide](Documentation/SnapKit%203.0%20Migration%20Guide.md)
-
-## Communication
-
-- If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/snapkit). (Tag 'snapkit')
-- If you'd like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/snapkit).
-- If you **found a bug**, open an issue.
-- If you **have a feature request**, open an issue.
-- If you **want to contribute**, submit a pull request.
-
-
-## Installation
-
-### CocoaPods
-
-[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command:
-
-```bash
-$ gem install cocoapods
-```
-
-> CocoaPods 1.1.0+ is required to build SnapKit 4.0.0+.
-
-To integrate SnapKit into your Xcode project using CocoaPods, specify it in your `Podfile`:
-
-```ruby
-source 'https://github.com/CocoaPods/Specs.git'
-platform :ios, '10.0'
-use_frameworks!
-
-target '<Your Target Name>' do
- pod 'SnapKit', '~> 5.7.0'
-end
-```
-
-Then, run the following command:
-
-```bash
-$ pod install
-```
-
-### Carthage
-
-[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
-
-You can install Carthage with [Homebrew](http://brew.sh/) using the following command:
-
-```bash
-$ brew update
-$ brew install carthage
-```
-
-To integrate SnapKit into your Xcode project using Carthage, specify it in your `Cartfile`:
-
-```ogdl
-github "SnapKit/SnapKit" ~> 5.0.0
-```
-
-Run `carthage update` to build the framework and drag the built `SnapKit.framework` into your Xcode project.
-
-### Swift Package Manager
-
-[Swift Package Manager](https://swift.org/package-manager/) is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.
-
-> Xcode 11+ is required to build SnapKit using Swift Package Manager.
-
-To integrate SnapKit into your Xcode project using Swift Package Manager, add it to the dependencies value of your `Package.swift`:
-
-```swift
-dependencies: [
- .package(url: "https://github.com/SnapKit/SnapKit.git", .upToNextMajor(from: "5.0.1"))
-]
-```
-
-### Manually
-
-If you prefer not to use either of the aforementioned dependency managers, you can integrate SnapKit into your project manually.
-
----
-
-## Usage
-
-### Quick Start
-
-```swift
-import SnapKit
-
-class MyViewController: UIViewController {
-
- lazy var box = UIView()
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- self.view.addSubview(box)
- box.backgroundColor = .green
- box.snp.makeConstraints { (make) -> Void in
- make.width.height.equalTo(50)
- make.center.equalTo(self.view)
- }
- }
-
-}
-```
-
-### Playground
-You can try SnapKit in Playground.
-
-**Note:**
-
-> To try SnapKit in playground, open `SnapKit.xcworkspace` and build SnapKit.framework for any simulator first.
-
-### Resources
-
-- [Documentation](https://snapkit.github.io/SnapKit/docs/)
-- [F.A.Q.](https://snapkit.github.io/SnapKit/faq/)
-
-## Credits
-
-- Robert Payne ([@robertjpayne](https://twitter.com/robertjpayne))
-- Many other contributors
-
-## License
-
-SnapKit is released under the MIT license. See LICENSE for details.
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-public final class Constraint {
-
- internal let sourceLocation: (String, UInt)
- internal let label: String?
-
- private let from: ConstraintItem
- private let to: ConstraintItem
- private let relation: ConstraintRelation
- private let multiplier: ConstraintMultiplierTarget
- private var constant: ConstraintConstantTarget {
- didSet {
- self.updateConstantAndPriorityIfNeeded()
- }
- }
- private var priority: ConstraintPriorityTarget {
- didSet {
- self.updateConstantAndPriorityIfNeeded()
- }
- }
- public var layoutConstraints: [LayoutConstraint]
-
- public var isActive: Bool {
- set {
- if newValue {
- activate()
- }
- else {
- deactivate()
- }
- }
-
- get {
- for layoutConstraint in self.layoutConstraints {
- if layoutConstraint.isActive {
- return true
- }
- }
- return false
- }
- }
-
- // MARK: Initialization
-
- internal init(from: ConstraintItem,
- to: ConstraintItem,
- relation: ConstraintRelation,
- sourceLocation: (String, UInt),
- label: String?,
- multiplier: ConstraintMultiplierTarget,
- constant: ConstraintConstantTarget,
- priority: ConstraintPriorityTarget) {
- self.from = from
- self.to = to
- self.relation = relation
- self.sourceLocation = sourceLocation
- self.label = label
- self.multiplier = multiplier
- self.constant = constant
- self.priority = priority
- self.layoutConstraints = []
-
- // get attributes
- let layoutFromAttributes = self.from.attributes.layoutAttributes
- let layoutToAttributes = self.to.attributes.layoutAttributes
-
- // get layout from
- let layoutFrom = self.from.layoutConstraintItem!
-
- // get relation
- let layoutRelation = self.relation.layoutRelation
-
- for layoutFromAttribute in layoutFromAttributes {
- // get layout to attribute
- let layoutToAttribute: LayoutAttribute
- #if canImport(UIKit)
- if layoutToAttributes.count > 0 {
- if self.from.attributes == .edges && self.to.attributes == .margins {
- switch layoutFromAttribute {
- case .left:
- layoutToAttribute = .leftMargin
- case .right:
- layoutToAttribute = .rightMargin
- case .top:
- layoutToAttribute = .topMargin
- case .bottom:
- layoutToAttribute = .bottomMargin
- default:
- fatalError()
- }
- } else if self.from.attributes == .margins && self.to.attributes == .edges {
- switch layoutFromAttribute {
- case .leftMargin:
- layoutToAttribute = .left
- case .rightMargin:
- layoutToAttribute = .right
- case .topMargin:
- layoutToAttribute = .top
- case .bottomMargin:
- layoutToAttribute = .bottom
- default:
- fatalError()
- }
- } else if self.from.attributes == .directionalEdges && self.to.attributes == .directionalMargins {
- switch layoutFromAttribute {
- case .leading:
- layoutToAttribute = .leadingMargin
- case .trailing:
- layoutToAttribute = .trailingMargin
- case .top:
- layoutToAttribute = .topMargin
- case .bottom:
- layoutToAttribute = .bottomMargin
- default:
- fatalError()
- }
- } else if self.from.attributes == .directionalMargins && self.to.attributes == .directionalEdges {
- switch layoutFromAttribute {
- case .leadingMargin:
- layoutToAttribute = .leading
- case .trailingMargin:
- layoutToAttribute = .trailing
- case .topMargin:
- layoutToAttribute = .top
- case .bottomMargin:
- layoutToAttribute = .bottom
- default:
- fatalError()
- }
- } else if self.from.attributes == self.to.attributes {
- layoutToAttribute = layoutFromAttribute
- } else {
- layoutToAttribute = layoutToAttributes[0]
- }
- } else {
- if self.to.target == nil && (layoutFromAttribute == .centerX || layoutFromAttribute == .centerY) {
- layoutToAttribute = layoutFromAttribute == .centerX ? .left : .top
- } else {
- layoutToAttribute = layoutFromAttribute
- }
- }
- #else
- if self.from.attributes == self.to.attributes {
- layoutToAttribute = layoutFromAttribute
- } else if layoutToAttributes.count > 0 {
- layoutToAttribute = layoutToAttributes[0]
- } else {
- layoutToAttribute = layoutFromAttribute
- }
- #endif
-
- // get layout constant
- let layoutConstant: CGFloat = self.constant.constraintConstantTargetValueFor(layoutAttribute: layoutToAttribute)
-
- // get layout to
- var layoutTo: AnyObject? = self.to.target
-
- // use superview if possible
- if layoutTo == nil && layoutToAttribute != .width && layoutToAttribute != .height {
- layoutTo = layoutFrom.superview
- }
-
- // create layout constraint
- let layoutConstraint = LayoutConstraint(
- item: layoutFrom,
- attribute: layoutFromAttribute,
- relatedBy: layoutRelation,
- toItem: layoutTo,
- attribute: layoutToAttribute,
- multiplier: self.multiplier.constraintMultiplierTargetValue,
- constant: layoutConstant
- )
-
- // set label
- layoutConstraint.label = self.label
-
- // set priority
- layoutConstraint.priority = LayoutPriority(rawValue: self.priority.constraintPriorityTargetValue)
-
- // set constraint
- layoutConstraint.constraint = self
-
- // append
- self.layoutConstraints.append(layoutConstraint)
- }
- }
-
- // MARK: Public
-
- @available(*, deprecated, renamed:"activate()")
- public func install() {
- self.activate()
- }
-
- @available(*, deprecated, renamed:"deactivate()")
- public func uninstall() {
- self.deactivate()
- }
-
- public func activate() {
- self.activateIfNeeded()
- }
-
- public func deactivate() {
- self.deactivateIfNeeded()
- }
-
- @discardableResult
- public func update(offset: ConstraintOffsetTarget) -> Constraint {
- self.constant = offset.constraintOffsetTargetValue
- return self
- }
-
- @discardableResult
- public func update(inset: ConstraintInsetTarget) -> Constraint {
- self.constant = inset.constraintInsetTargetValue
- return self
- }
-
- #if canImport(UIKit)
- @discardableResult
- @available(iOS 11.0, tvOS 11.0, *)
- public func update(inset: ConstraintDirectionalInsetTarget) -> Constraint {
- self.constant = inset.constraintDirectionalInsetTargetValue
- return self
- }
- #endif
-
- @discardableResult
- public func update(priority: ConstraintPriorityTarget) -> Constraint {
- self.priority = priority.constraintPriorityTargetValue
- return self
- }
-
- @discardableResult
- public func update(priority: ConstraintPriority) -> Constraint {
- self.priority = priority.value
- return self
- }
-
- @available(*, deprecated, renamed:"update(offset:)")
- public func updateOffset(amount: ConstraintOffsetTarget) -> Void { self.update(offset: amount) }
-
- @available(*, deprecated, renamed:"update(inset:)")
- public func updateInsets(amount: ConstraintInsetTarget) -> Void { self.update(inset: amount) }
-
- @available(*, deprecated, renamed:"update(priority:)")
- public func updatePriority(amount: ConstraintPriorityTarget) -> Void { self.update(priority: amount) }
-
- @available(*, deprecated, message:"Use update(priority: ConstraintPriorityTarget) instead.")
- public func updatePriorityRequired() -> Void {}
-
- @available(*, deprecated, message:"Use update(priority: ConstraintPriorityTarget) instead.")
- public func updatePriorityHigh() -> Void { fatalError("Must be implemented by Concrete subclass.") }
-
- @available(*, deprecated, message:"Use update(priority: ConstraintPriorityTarget) instead.")
- public func updatePriorityMedium() -> Void { fatalError("Must be implemented by Concrete subclass.") }
-
- @available(*, deprecated, message:"Use update(priority: ConstraintPriorityTarget) instead.")
- public func updatePriorityLow() -> Void { fatalError("Must be implemented by Concrete subclass.") }
-
- // MARK: Internal
-
- internal func updateConstantAndPriorityIfNeeded() {
- for layoutConstraint in self.layoutConstraints {
- let attribute = (layoutConstraint.secondAttribute == .notAnAttribute) ? layoutConstraint.firstAttribute : layoutConstraint.secondAttribute
- layoutConstraint.constant = self.constant.constraintConstantTargetValueFor(layoutAttribute: attribute)
-
- let requiredPriority = ConstraintPriority.required.value
- if (layoutConstraint.priority.rawValue < requiredPriority), (self.priority.constraintPriorityTargetValue != requiredPriority) {
- layoutConstraint.priority = LayoutPriority(rawValue: self.priority.constraintPriorityTargetValue)
- }
- }
- }
-
- internal func activateIfNeeded(updatingExisting: Bool = false) {
- guard let item = self.from.layoutConstraintItem else {
- print("WARNING: SnapKit failed to get from item from constraint. Activate will be a no-op.")
- return
- }
- let layoutConstraints = self.layoutConstraints
-
- if updatingExisting {
- var existingLayoutConstraints: [LayoutConstraint] = []
- for constraint in item.constraints {
- existingLayoutConstraints += constraint.layoutConstraints
- }
-
- for layoutConstraint in layoutConstraints {
- let existingLayoutConstraint = existingLayoutConstraints.first { $0 == layoutConstraint }
- guard let updateLayoutConstraint = existingLayoutConstraint else {
- fatalError("Updated constraint could not find existing matching constraint to update: \(layoutConstraint)")
- }
-
- let updateLayoutAttribute = (updateLayoutConstraint.secondAttribute == .notAnAttribute) ? updateLayoutConstraint.firstAttribute : updateLayoutConstraint.secondAttribute
- updateLayoutConstraint.constant = self.constant.constraintConstantTargetValueFor(layoutAttribute: updateLayoutAttribute)
- }
- } else {
- NSLayoutConstraint.activate(layoutConstraints)
- item.add(constraints: [self])
- }
- }
-
- internal func deactivateIfNeeded() {
- guard let item = self.from.layoutConstraintItem else {
- print("WARNING: SnapKit failed to get from item from constraint. Deactivate will be a no-op.")
- return
- }
- let layoutConstraints = self.layoutConstraints
- NSLayoutConstraint.deactivate(layoutConstraints)
- item.remove(constraints: [self])
- }
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-internal struct ConstraintAttributes : OptionSet, ExpressibleByIntegerLiteral {
-
- typealias IntegerLiteralType = UInt
-
- internal init(rawValue: UInt) {
- self.rawValue = rawValue
- }
- internal init(_ rawValue: UInt) {
- self.init(rawValue: rawValue)
- }
- internal init(nilLiteral: ()) {
- self.rawValue = 0
- }
- internal init(integerLiteral rawValue: IntegerLiteralType) {
- self.init(rawValue: rawValue)
- }
-
- internal private(set) var rawValue: UInt
- internal static var allZeros: ConstraintAttributes { return 0 }
- internal static func convertFromNilLiteral() -> ConstraintAttributes { return 0 }
- internal var boolValue: Bool { return self.rawValue != 0 }
-
- internal func toRaw() -> UInt { return self.rawValue }
- internal static func fromRaw(_ raw: UInt) -> ConstraintAttributes? { return self.init(raw) }
- internal static func fromMask(_ raw: UInt) -> ConstraintAttributes { return self.init(raw) }
-
- // normal
-
- internal static let none: ConstraintAttributes = 0
- internal static let left: ConstraintAttributes = ConstraintAttributes(UInt(1) << 0)
- internal static let top: ConstraintAttributes = ConstraintAttributes(UInt(1) << 1)
- internal static let right: ConstraintAttributes = ConstraintAttributes(UInt(1) << 2)
- internal static let bottom: ConstraintAttributes = ConstraintAttributes(UInt(1) << 3)
- internal static let leading: ConstraintAttributes = ConstraintAttributes(UInt(1) << 4)
- internal static let trailing: ConstraintAttributes = ConstraintAttributes(UInt(1) << 5)
- internal static let width: ConstraintAttributes = ConstraintAttributes(UInt(1) << 6)
- internal static let height: ConstraintAttributes = ConstraintAttributes(UInt(1) << 7)
- internal static let centerX: ConstraintAttributes = ConstraintAttributes(UInt(1) << 8)
- internal static let centerY: ConstraintAttributes = ConstraintAttributes(UInt(1) << 9)
- internal static let lastBaseline: ConstraintAttributes = ConstraintAttributes(UInt(1) << 10)
-
- @available(iOS 8.0, OSX 10.11, *)
- internal static let firstBaseline: ConstraintAttributes = ConstraintAttributes(UInt(1) << 11)
-
- @available(iOS 8.0, *)
- internal static let leftMargin: ConstraintAttributes = ConstraintAttributes(UInt(1) << 12)
-
- @available(iOS 8.0, *)
- internal static let rightMargin: ConstraintAttributes = ConstraintAttributes(UInt(1) << 13)
-
- @available(iOS 8.0, *)
- internal static let topMargin: ConstraintAttributes = ConstraintAttributes(UInt(1) << 14)
-
- @available(iOS 8.0, *)
- internal static let bottomMargin: ConstraintAttributes = ConstraintAttributes(UInt(1) << 15)
-
- @available(iOS 8.0, *)
- internal static let leadingMargin: ConstraintAttributes = ConstraintAttributes(UInt(1) << 16)
-
- @available(iOS 8.0, *)
- internal static let trailingMargin: ConstraintAttributes = ConstraintAttributes(UInt(1) << 17)
-
- @available(iOS 8.0, *)
- internal static let centerXWithinMargins: ConstraintAttributes = ConstraintAttributes(UInt(1) << 18)
-
- @available(iOS 8.0, *)
- internal static let centerYWithinMargins: ConstraintAttributes = ConstraintAttributes(UInt(1) << 19)
-
- // aggregates
-
- internal static let edges: ConstraintAttributes = [.horizontalEdges, .verticalEdges]
- internal static let horizontalEdges: ConstraintAttributes = [.left, .right]
- internal static let verticalEdges: ConstraintAttributes = [.top, .bottom]
- internal static let directionalEdges: ConstraintAttributes = [.directionalHorizontalEdges, .directionalVerticalEdges]
- internal static let directionalHorizontalEdges: ConstraintAttributes = [.leading, .trailing]
- internal static let directionalVerticalEdges: ConstraintAttributes = [.top, .bottom]
- internal static let size: ConstraintAttributes = [.width, .height]
- internal static let center: ConstraintAttributes = [.centerX, .centerY]
-
- @available(iOS 8.0, *)
- internal static let margins: ConstraintAttributes = [.leftMargin, .topMargin, .rightMargin, .bottomMargin]
-
- @available(iOS 8.0, *)
- internal static let directionalMargins: ConstraintAttributes = [.leadingMargin, .topMargin, .trailingMargin, .bottomMargin]
-
- @available(iOS 8.0, *)
- internal static let centerWithinMargins: ConstraintAttributes = [.centerXWithinMargins, .centerYWithinMargins]
-
- internal var layoutAttributes:[LayoutAttribute] {
- var attrs = [LayoutAttribute]()
- if (self.contains(ConstraintAttributes.left)) {
- attrs.append(.left)
- }
- if (self.contains(ConstraintAttributes.top)) {
- attrs.append(.top)
- }
- if (self.contains(ConstraintAttributes.right)) {
- attrs.append(.right)
- }
- if (self.contains(ConstraintAttributes.bottom)) {
- attrs.append(.bottom)
- }
- if (self.contains(ConstraintAttributes.leading)) {
- attrs.append(.leading)
- }
- if (self.contains(ConstraintAttributes.trailing)) {
- attrs.append(.trailing)
- }
- if (self.contains(ConstraintAttributes.width)) {
- attrs.append(.width)
- }
- if (self.contains(ConstraintAttributes.height)) {
- attrs.append(.height)
- }
- if (self.contains(ConstraintAttributes.centerX)) {
- attrs.append(.centerX)
- }
- if (self.contains(ConstraintAttributes.centerY)) {
- attrs.append(.centerY)
- }
- if (self.contains(ConstraintAttributes.lastBaseline)) {
- attrs.append(.lastBaseline)
- }
-
- #if canImport(UIKit)
- if (self.contains(ConstraintAttributes.firstBaseline)) {
- attrs.append(.firstBaseline)
- }
- if (self.contains(ConstraintAttributes.leftMargin)) {
- attrs.append(.leftMargin)
- }
- if (self.contains(ConstraintAttributes.rightMargin)) {
- attrs.append(.rightMargin)
- }
- if (self.contains(ConstraintAttributes.topMargin)) {
- attrs.append(.topMargin)
- }
- if (self.contains(ConstraintAttributes.bottomMargin)) {
- attrs.append(.bottomMargin)
- }
- if (self.contains(ConstraintAttributes.leadingMargin)) {
- attrs.append(.leadingMargin)
- }
- if (self.contains(ConstraintAttributes.trailingMargin)) {
- attrs.append(.trailingMargin)
- }
- if (self.contains(ConstraintAttributes.centerXWithinMargins)) {
- attrs.append(.centerXWithinMargins)
- }
- if (self.contains(ConstraintAttributes.centerYWithinMargins)) {
- attrs.append(.centerYWithinMargins)
- }
- #endif
-
- return attrs
- }
-}
-
-internal func + (left: ConstraintAttributes, right: ConstraintAttributes) -> ConstraintAttributes {
- return left.union(right)
-}
-
-internal func +=(left: inout ConstraintAttributes, right: ConstraintAttributes) {
- left.formUnion(right)
-}
-
-internal func -=(left: inout ConstraintAttributes, right: ConstraintAttributes) {
- left.subtract(right)
-}
-
-internal func ==(left: ConstraintAttributes, right: ConstraintAttributes) -> Bool {
- return left.rawValue == right.rawValue
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
- public typealias ConstraintInterfaceLayoutDirection = UIUserInterfaceLayoutDirection
-#else
- import AppKit
- public typealias ConstraintInterfaceLayoutDirection = NSUserInterfaceLayoutDirection
-#endif
-
-
-public struct ConstraintConfig {
-
- public static var interfaceLayoutDirection: ConstraintInterfaceLayoutDirection = .leftToRight
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public protocol ConstraintConstantTarget {
-}
-
-extension CGPoint: ConstraintConstantTarget {
-}
-
-extension CGSize: ConstraintConstantTarget {
-}
-
-extension ConstraintInsets: ConstraintConstantTarget {
-}
-
-#if canImport(UIKit)
-@available(iOS 11.0, tvOS 11.0, *)
-extension ConstraintDirectionalInsets: ConstraintConstantTarget {
-}
-#endif
-
-extension ConstraintConstantTarget {
-
- internal func constraintConstantTargetValueFor(layoutAttribute: LayoutAttribute) -> CGFloat {
- if let value = self as? CGFloat {
- return value
- }
-
- if let value = self as? Float {
- return CGFloat(value)
- }
-
- if let value = self as? Double {
- return CGFloat(value)
- }
-
- if let value = self as? Int {
- return CGFloat(value)
- }
-
- if let value = self as? UInt {
- return CGFloat(value)
- }
-
- if let value = self as? CGSize {
- if layoutAttribute == .width {
- return value.width
- } else if layoutAttribute == .height {
- return value.height
- } else {
- return 0.0
- }
- }
-
- if let value = self as? CGPoint {
- #if canImport(UIKit)
- switch layoutAttribute {
- case .left, .right, .leading, .trailing, .centerX, .leftMargin, .rightMargin, .leadingMargin, .trailingMargin, .centerXWithinMargins:
- return value.x
- case .top, .bottom, .centerY, .topMargin, .bottomMargin, .centerYWithinMargins, .lastBaseline, .firstBaseline:
- return value.y
- case .width, .height, .notAnAttribute:
- return 0.0
- #if swift(>=5.0)
- @unknown default:
- return 0.0
- #endif
- }
- #else
- switch layoutAttribute {
- case .left, .right, .leading, .trailing, .centerX:
- return value.x
- case .top, .bottom, .centerY, .lastBaseline, .firstBaseline:
- return value.y
- case .width, .height, .notAnAttribute:
- return 0.0
- #if swift(>=5.0)
- @unknown default:
- return 0.0
- #endif
- }
- #endif
- }
-
- if let value = self as? ConstraintInsets {
- #if canImport(UIKit)
- switch layoutAttribute {
- case .left, .leftMargin:
- return value.left
- case .top, .topMargin, .firstBaseline:
- return value.top
- case .right, .rightMargin:
- return -value.right
- case .bottom, .bottomMargin, .lastBaseline:
- return -value.bottom
- case .leading, .leadingMargin:
- return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? value.left : value.right
- case .trailing, .trailingMargin:
- return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? -value.right : -value.left
- case .centerX, .centerXWithinMargins:
- return (value.left - value.right) / 2
- case .centerY, .centerYWithinMargins:
- return (value.top - value.bottom) / 2
- case .width:
- return -(value.left + value.right)
- case .height:
- return -(value.top + value.bottom)
- case .notAnAttribute:
- return 0.0
- #if swift(>=5.0)
- @unknown default:
- return 0.0
- #endif
- }
- #else
- switch layoutAttribute {
- case .left:
- return value.left
- case .top, .firstBaseline:
- return value.top
- case .right:
- return -value.right
- case .bottom, .lastBaseline:
- return -value.bottom
- case .leading:
- return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? value.left : value.right
- case .trailing:
- return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? -value.right : -value.left
- case .centerX:
- return (value.left - value.right) / 2
- case .centerY:
- return (value.top - value.bottom) / 2
- case .width:
- return -(value.left + value.right)
- case .height:
- return -(value.top + value.bottom)
- case .notAnAttribute:
- return 0.0
- #if swift(>=5.0)
- @unknown default:
- return 0.0
- #endif
- }
- #endif
- }
-
- #if canImport(UIKit)
- if #available(iOS 11.0, tvOS 11.0, *), let value = self as? ConstraintDirectionalInsets {
- switch layoutAttribute {
- case .left, .leftMargin:
- return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? value.leading : value.trailing
- case .top, .topMargin, .firstBaseline:
- return value.top
- case .right, .rightMargin:
- return (ConstraintConfig.interfaceLayoutDirection == .leftToRight) ? -value.trailing : -value.leading
- case .bottom, .bottomMargin, .lastBaseline:
- return -value.bottom
- case .leading, .leadingMargin:
- return value.leading
- case .trailing, .trailingMargin:
- return -value.trailing
- case .centerX, .centerXWithinMargins:
- return (value.leading - value.trailing) / 2
- case .centerY, .centerYWithinMargins:
- return (value.top - value.bottom) / 2
- case .width:
- return -(value.leading + value.trailing)
- case .height:
- return -(value.top + value.bottom)
- case .notAnAttribute:
- return 0.0
- #if swift(>=5.0)
- @unknown default:
- return 0.0
- #else
- default:
- return 0.0
- #endif
- }
- }
- #endif
-
- return 0.0
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public protocol ConstraintDSL {
-
- var target: AnyObject? { get }
-
- func setLabel(_ value: String?)
- func label() -> String?
-
-}
-extension ConstraintDSL {
-
- public func setLabel(_ value: String?) {
- objc_setAssociatedObject(self.target as Any, &labelKey, value, .OBJC_ASSOCIATION_COPY_NONATOMIC)
- }
- public func label() -> String? {
- return objc_getAssociatedObject(self.target as Any, &labelKey) as? String
- }
-
-}
-private var labelKey: UInt8 = 0
-
-
-public protocol ConstraintBasicAttributesDSL : ConstraintDSL {
-}
-extension ConstraintBasicAttributesDSL {
-
- // MARK: Basics
-
- public var left: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.left)
- }
-
- public var top: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.top)
- }
-
- public var right: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.right)
- }
-
- public var bottom: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottom)
- }
-
- public var leading: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.leading)
- }
-
- public var trailing: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.trailing)
- }
-
- public var width: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.width)
- }
-
- public var height: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.height)
- }
-
- public var centerX: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerX)
- }
-
- public var centerY: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerY)
- }
-
- public var edges: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.edges)
- }
-
- public var directionalEdges: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.directionalEdges)
- }
-
- public var horizontalEdges: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.horizontalEdges)
- }
-
- public var verticalEdges: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.verticalEdges)
- }
-
- public var directionalHorizontalEdges: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.directionalHorizontalEdges)
- }
-
- public var directionalVerticalEdges: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.directionalVerticalEdges)
- }
-
- public var size: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.size)
- }
-
- public var center: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.center)
- }
-
-}
-
-public protocol ConstraintAttributesDSL : ConstraintBasicAttributesDSL {
-}
-extension ConstraintAttributesDSL {
-
- // MARK: Baselines
- @available(*, deprecated, renamed:"lastBaseline")
- public var baseline: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.lastBaseline)
- }
-
- @available(iOS 8.0, OSX 10.11, *)
- public var lastBaseline: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.lastBaseline)
- }
-
- @available(iOS 8.0, OSX 10.11, *)
- public var firstBaseline: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.firstBaseline)
- }
-
- // MARK: Margins
-
- @available(iOS 8.0, *)
- public var leftMargin: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.leftMargin)
- }
-
- @available(iOS 8.0, *)
- public var topMargin: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.topMargin)
- }
-
- @available(iOS 8.0, *)
- public var rightMargin: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.rightMargin)
- }
-
- @available(iOS 8.0, *)
- public var bottomMargin: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottomMargin)
- }
-
- @available(iOS 8.0, *)
- public var leadingMargin: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.leadingMargin)
- }
-
- @available(iOS 8.0, *)
- public var trailingMargin: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.trailingMargin)
- }
-
- @available(iOS 8.0, *)
- public var centerXWithinMargins: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerXWithinMargins)
- }
-
- @available(iOS 8.0, *)
- public var centerYWithinMargins: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerYWithinMargins)
- }
-
- @available(iOS 8.0, *)
- public var margins: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.margins)
- }
-
- @available(iOS 8.0, *)
- public var directionalMargins: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.directionalMargins)
- }
-
- @available(iOS 8.0, *)
- public var centerWithinMargins: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.centerWithinMargins)
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public class ConstraintDescription {
-
- internal let item: LayoutConstraintItem
- internal var attributes: ConstraintAttributes
- internal var relation: ConstraintRelation? = nil
- internal var sourceLocation: (String, UInt)? = nil
- internal var label: String? = nil
- internal var related: ConstraintItem? = nil
- internal var multiplier: ConstraintMultiplierTarget = 1.0
- internal var constant: ConstraintConstantTarget = 0.0
- internal var priority: ConstraintPriorityTarget = 1000.0
- internal lazy var constraint: Constraint? = {
- guard let relation = self.relation,
- let related = self.related,
- let sourceLocation = self.sourceLocation else {
- return nil
- }
- let from = ConstraintItem(target: self.item, attributes: self.attributes)
-
- return Constraint(
- from: from,
- to: related,
- relation: relation,
- sourceLocation: sourceLocation,
- label: self.label,
- multiplier: self.multiplier,
- constant: self.constant,
- priority: self.priority
- )
- }()
-
- // MARK: Initialization
-
- internal init(item: LayoutConstraintItem, attributes: ConstraintAttributes) {
- self.item = item
- self.attributes = attributes
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
-import UIKit
-#else
-import AppKit
-#endif
-
-#if canImport(UIKit)
-public protocol ConstraintDirectionalInsetTarget: ConstraintConstantTarget {
-}
-
-@available(iOS 11.0, tvOS 11.0, *)
-extension ConstraintDirectionalInsets: ConstraintDirectionalInsetTarget {
-}
-
-extension ConstraintDirectionalInsetTarget {
-
- @available(iOS 11.0, tvOS 11.0, *)
- internal var constraintDirectionalInsetTargetValue: ConstraintDirectionalInsets {
- if let amount = self as? ConstraintDirectionalInsets {
- return amount
- } else {
- return ConstraintDirectionalInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
- }
- }
-}
-#endif
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-#if canImport(UIKit)
- @available(iOS 11.0, tvOS 11.0, *)
- public typealias ConstraintDirectionalInsets = NSDirectionalEdgeInsets
-#endif
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public protocol ConstraintInsetTarget: ConstraintConstantTarget {
-}
-
-extension Int: ConstraintInsetTarget {
-}
-
-extension UInt: ConstraintInsetTarget {
-}
-
-extension Float: ConstraintInsetTarget {
-}
-
-extension Double: ConstraintInsetTarget {
-}
-
-extension CGFloat: ConstraintInsetTarget {
-}
-
-extension ConstraintInsets: ConstraintInsetTarget {
-}
-
-extension ConstraintInsetTarget {
-
- internal var constraintInsetTargetValue: ConstraintInsets {
- if let amount = self as? ConstraintInsets {
- return amount
- } else if let amount = self as? Float {
- return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
- } else if let amount = self as? Double {
- return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
- } else if let amount = self as? CGFloat {
- return ConstraintInsets(top: amount, left: amount, bottom: amount, right: amount)
- } else if let amount = self as? Int {
- return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
- } else if let amount = self as? UInt {
- return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount))
- } else {
- return ConstraintInsets(top: 0, left: 0, bottom: 0, right: 0)
- }
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-#if canImport(UIKit)
- public typealias ConstraintInsets = UIEdgeInsets
-#else
- public typealias ConstraintInsets = NSEdgeInsets
-#endif
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public final class ConstraintItem {
-
- internal weak var target: AnyObject?
- internal let attributes: ConstraintAttributes
-
- internal init(target: AnyObject?, attributes: ConstraintAttributes) {
- self.target = target
- self.attributes = attributes
- }
-
- internal var layoutConstraintItem: LayoutConstraintItem? {
- return self.target as? LayoutConstraintItem
- }
-
-}
-
-public func ==(lhs: ConstraintItem, rhs: ConstraintItem) -> Bool {
- // pointer equality
- guard lhs !== rhs else {
- return true
- }
-
- // must both have valid targets and identical attributes
- guard let target1 = lhs.target,
- let target2 = rhs.target,
- target1 === target2 && lhs.attributes == rhs.attributes else {
- return false
- }
-
- return true
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#endif
-
-
-@available(iOS 9.0, OSX 10.11, *)
-public extension ConstraintLayoutGuide {
-
- var snp: ConstraintLayoutGuideDSL {
- return ConstraintLayoutGuideDSL(guide: self)
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-#if canImport(UIKit)
- @available(iOS 9.0, *)
- public typealias ConstraintLayoutGuide = UILayoutGuide
-#else
- @available(OSX 10.11, *)
- public typealias ConstraintLayoutGuide = NSLayoutGuide
-#endif
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-@available(iOS 9.0, OSX 10.11, *)
-public struct ConstraintLayoutGuideDSL: ConstraintAttributesDSL {
-
- @discardableResult
- public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
- return ConstraintMaker.prepareConstraints(item: self.guide, closure: closure)
- }
-
- public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
- ConstraintMaker.makeConstraints(item: self.guide, closure: closure)
- }
-
- public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
- ConstraintMaker.remakeConstraints(item: self.guide, closure: closure)
- }
-
- public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
- ConstraintMaker.updateConstraints(item: self.guide, closure: closure)
- }
-
- public func removeConstraints() {
- ConstraintMaker.removeConstraints(item: self.guide)
- }
-
- public var target: AnyObject? {
- return self.guide
- }
-
- internal let guide: ConstraintLayoutGuide
-
- internal init(guide: ConstraintLayoutGuide) {
- self.guide = guide
-
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-#if canImport(UIKit)
- @available(iOS 8.0, *)
- public typealias ConstraintLayoutSupport = UILayoutSupport
-#else
- public class ConstraintLayoutSupport {}
-#endif
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-@available(iOS 8.0, *)
-public struct ConstraintLayoutSupportDSL: ConstraintDSL {
-
- public var target: AnyObject? {
- return self.support
- }
-
- internal let support: ConstraintLayoutSupport
-
- internal init(support: ConstraintLayoutSupport) {
- self.support = support
-
- }
-
- public var top: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.top)
- }
-
- public var bottom: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottom)
- }
-
- public var height: ConstraintItem {
- return ConstraintItem(target: self.target, attributes: ConstraintAttributes.height)
- }
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-public class ConstraintMaker {
-
- public var left: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.left)
- }
-
- public var top: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.top)
- }
-
- public var bottom: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.bottom)
- }
-
- public var right: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.right)
- }
-
- public var leading: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.leading)
- }
-
- public var trailing: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.trailing)
- }
-
- public var width: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.width)
- }
-
- public var height: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.height)
- }
-
- public var centerX: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.centerX)
- }
-
- public var centerY: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.centerY)
- }
-
- @available(*, deprecated, renamed:"lastBaseline")
- public var baseline: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.lastBaseline)
- }
-
- public var lastBaseline: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.lastBaseline)
- }
-
- @available(iOS 8.0, OSX 10.11, *)
- public var firstBaseline: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.firstBaseline)
- }
-
- @available(iOS 8.0, *)
- public var leftMargin: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.leftMargin)
- }
-
- @available(iOS 8.0, *)
- public var rightMargin: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.rightMargin)
- }
-
- @available(iOS 8.0, *)
- public var topMargin: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.topMargin)
- }
-
- @available(iOS 8.0, *)
- public var bottomMargin: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.bottomMargin)
- }
-
- @available(iOS 8.0, *)
- public var leadingMargin: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.leadingMargin)
- }
-
- @available(iOS 8.0, *)
- public var trailingMargin: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.trailingMargin)
- }
-
- @available(iOS 8.0, *)
- public var centerXWithinMargins: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.centerXWithinMargins)
- }
-
- @available(iOS 8.0, *)
- public var centerYWithinMargins: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.centerYWithinMargins)
- }
-
- public var edges: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.edges)
- }
- public var horizontalEdges: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.horizontalEdges)
- }
- public var verticalEdges: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.verticalEdges)
- }
- public var directionalEdges: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.directionalEdges)
- }
- public var directionalHorizontalEdges: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.directionalHorizontalEdges)
- }
- public var directionalVerticalEdges: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.directionalVerticalEdges)
- }
- public var size: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.size)
- }
- public var center: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.center)
- }
-
- @available(iOS 8.0, *)
- public var margins: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.margins)
- }
-
- @available(iOS 8.0, *)
- public var directionalMargins: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.directionalMargins)
- }
-
- @available(iOS 8.0, *)
- public var centerWithinMargins: ConstraintMakerExtendable {
- return self.makeExtendableWithAttributes(.centerWithinMargins)
- }
-
- public let item: LayoutConstraintItem
- private var descriptions = [ConstraintDescription]()
-
- internal init(item: LayoutConstraintItem) {
- self.item = item
- self.item.prepare()
- }
-
- internal func makeExtendableWithAttributes(_ attributes: ConstraintAttributes) -> ConstraintMakerExtendable {
- let description = ConstraintDescription(item: self.item, attributes: attributes)
- self.descriptions.append(description)
- return ConstraintMakerExtendable(description)
- }
-
- internal static func prepareConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
- let maker = ConstraintMaker(item: item)
- closure(maker)
- var constraints: [Constraint] = []
- for description in maker.descriptions {
- guard let constraint = description.constraint else {
- continue
- }
- constraints.append(constraint)
- }
- return constraints
- }
-
- internal static func makeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
- let constraints = prepareConstraints(item: item, closure: closure)
- for constraint in constraints {
- constraint.activateIfNeeded(updatingExisting: false)
- }
- }
-
- internal static func remakeConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
- self.removeConstraints(item: item)
- self.makeConstraints(item: item, closure: closure)
- }
-
- internal static func updateConstraints(item: LayoutConstraintItem, closure: (_ make: ConstraintMaker) -> Void) {
- guard item.constraints.count > 0 else {
- self.makeConstraints(item: item, closure: closure)
- return
- }
-
- let constraints = prepareConstraints(item: item, closure: closure)
- for constraint in constraints {
- constraint.activateIfNeeded(updatingExisting: true)
- }
- }
-
- internal static func removeConstraints(item: LayoutConstraintItem) {
- let constraints = item.constraints
- for constraint in constraints {
- constraint.deactivateIfNeeded()
- }
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public class ConstraintMakerEditable: ConstraintMakerPrioritizable {
-
- @discardableResult
- public func multipliedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable {
- self.description.multiplier = amount
- return self
- }
-
- @discardableResult
- public func dividedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable {
- return self.multipliedBy(1.0 / amount.constraintMultiplierTargetValue)
- }
-
- @discardableResult
- public func offset(_ amount: ConstraintOffsetTarget) -> ConstraintMakerEditable {
- self.description.constant = amount.constraintOffsetTargetValue
- return self
- }
-
- @discardableResult
- public func inset(_ amount: ConstraintInsetTarget) -> ConstraintMakerEditable {
- self.description.constant = amount.constraintInsetTargetValue
- return self
- }
-
- #if canImport(UIKit)
- @discardableResult
- @available(iOS 11.0, tvOS 11.0, *)
- public func inset(_ amount: ConstraintDirectionalInsetTarget) -> ConstraintMakerEditable {
- self.description.constant = amount.constraintDirectionalInsetTargetValue
- return self
- }
- #endif
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public class ConstraintMakerExtendable: ConstraintMakerRelatable {
-
- public var left: ConstraintMakerExtendable {
- self.description.attributes += .left
- return self
- }
-
- public var top: ConstraintMakerExtendable {
- self.description.attributes += .top
- return self
- }
-
- public var bottom: ConstraintMakerExtendable {
- self.description.attributes += .bottom
- return self
- }
-
- public var right: ConstraintMakerExtendable {
- self.description.attributes += .right
- return self
- }
-
- public var leading: ConstraintMakerExtendable {
- self.description.attributes += .leading
- return self
- }
-
- public var trailing: ConstraintMakerExtendable {
- self.description.attributes += .trailing
- return self
- }
-
- public var width: ConstraintMakerExtendable {
- self.description.attributes += .width
- return self
- }
-
- public var height: ConstraintMakerExtendable {
- self.description.attributes += .height
- return self
- }
-
- public var centerX: ConstraintMakerExtendable {
- self.description.attributes += .centerX
- return self
- }
-
- public var centerY: ConstraintMakerExtendable {
- self.description.attributes += .centerY
- return self
- }
-
- @available(*, deprecated, renamed:"lastBaseline")
- public var baseline: ConstraintMakerExtendable {
- self.description.attributes += .lastBaseline
- return self
- }
-
- public var lastBaseline: ConstraintMakerExtendable {
- self.description.attributes += .lastBaseline
- return self
- }
-
- @available(iOS 8.0, OSX 10.11, *)
- public var firstBaseline: ConstraintMakerExtendable {
- self.description.attributes += .firstBaseline
- return self
- }
-
- @available(iOS 8.0, *)
- public var leftMargin: ConstraintMakerExtendable {
- self.description.attributes += .leftMargin
- return self
- }
-
- @available(iOS 8.0, *)
- public var rightMargin: ConstraintMakerExtendable {
- self.description.attributes += .rightMargin
- return self
- }
-
- @available(iOS 8.0, *)
- public var topMargin: ConstraintMakerExtendable {
- self.description.attributes += .topMargin
- return self
- }
-
- @available(iOS 8.0, *)
- public var bottomMargin: ConstraintMakerExtendable {
- self.description.attributes += .bottomMargin
- return self
- }
-
- @available(iOS 8.0, *)
- public var leadingMargin: ConstraintMakerExtendable {
- self.description.attributes += .leadingMargin
- return self
- }
-
- @available(iOS 8.0, *)
- public var trailingMargin: ConstraintMakerExtendable {
- self.description.attributes += .trailingMargin
- return self
- }
-
- @available(iOS 8.0, *)
- public var centerXWithinMargins: ConstraintMakerExtendable {
- self.description.attributes += .centerXWithinMargins
- return self
- }
-
- @available(iOS 8.0, *)
- public var centerYWithinMargins: ConstraintMakerExtendable {
- self.description.attributes += .centerYWithinMargins
- return self
- }
-
- public var edges: ConstraintMakerExtendable {
- self.description.attributes += .edges
- return self
- }
- public var horizontalEdges: ConstraintMakerExtendable {
- self.description.attributes += .horizontalEdges
- return self
- }
- public var verticalEdges: ConstraintMakerExtendable {
- self.description.attributes += .verticalEdges
- return self
- }
- public var directionalEdges: ConstraintMakerExtendable {
- self.description.attributes += .directionalEdges
- return self
- }
- public var directionalHorizontalEdges: ConstraintMakerExtendable {
- self.description.attributes += .directionalHorizontalEdges
- return self
- }
- public var directionalVerticalEdges: ConstraintMakerExtendable {
- self.description.attributes += .directionalVerticalEdges
- return self
- }
- public var size: ConstraintMakerExtendable {
- self.description.attributes += .size
- return self
- }
-
- @available(iOS 8.0, *)
- public var margins: ConstraintMakerExtendable {
- self.description.attributes += .margins
- return self
- }
-
- @available(iOS 8.0, *)
- public var directionalMargins: ConstraintMakerExtendable {
- self.description.attributes += .directionalMargins
- return self
- }
-
- @available(iOS 8.0, *)
- public var centerWithinMargins: ConstraintMakerExtendable {
- self.description.attributes += .centerWithinMargins
- return self
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public class ConstraintMakerFinalizable {
-
- internal let description: ConstraintDescription
-
- internal init(_ description: ConstraintDescription) {
- self.description = description
- }
-
- @discardableResult
- public func labeled(_ label: String) -> ConstraintMakerFinalizable {
- self.description.label = label
- return self
- }
-
- public var constraint: Constraint {
- return self.description.constraint!
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-@available(*, deprecated, message:"Use ConstraintMakerPrioritizable instead.")
-public typealias ConstraintMakerPriortizable = ConstraintMakerPrioritizable
-
-public class ConstraintMakerPrioritizable: ConstraintMakerFinalizable {
-
- @discardableResult
- public func priority(_ amount: ConstraintPriority) -> ConstraintMakerFinalizable {
- self.description.priority = amount.value
- return self
- }
-
- @discardableResult
- public func priority(_ amount: ConstraintPriorityTarget) -> ConstraintMakerFinalizable {
- self.description.priority = amount
- return self
- }
-
- @available(*, deprecated, message:"Use priority(.required) instead.")
- @discardableResult
- public func priorityRequired() -> ConstraintMakerFinalizable {
- return self.priority(.required)
- }
-
- @available(*, deprecated, message:"Use priority(.high) instead.")
- @discardableResult
- public func priorityHigh() -> ConstraintMakerFinalizable {
- return self.priority(.high)
- }
-
- @available(*, deprecated, message:"Use priority(.medium) instead.")
- @discardableResult
- public func priorityMedium() -> ConstraintMakerFinalizable {
- return self.priority(.medium)
- }
-
- @available(*, deprecated, message:"Use priority(.low) instead.")
- @discardableResult
- public func priorityLow() -> ConstraintMakerFinalizable {
- return self.priority(.low)
- }
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-extension ConstraintMakerRelatable {
-
- @discardableResult
- public func equalToSuperview<T: ConstraintRelatableTarget>(_ closure: (ConstraintView) -> T, _ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
- guard let other = self.description.item.superview else {
- fatalError("Expected superview but found nil when attempting make constraint `equalToSuperview`.")
- }
- return self.relatedTo(closure(other), relation: .equal, file: file, line: line)
- }
-
- @discardableResult
- public func lessThanOrEqualToSuperview<T: ConstraintRelatableTarget>(_ closure: (ConstraintView) -> T, _ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
- guard let other = self.description.item.superview else {
- fatalError("Expected superview but found nil when attempting make constraint `lessThanOrEqualToSuperview`.")
- }
- return self.relatedTo(closure(other), relation: .lessThanOrEqual, file: file, line: line)
- }
-
- @discardableResult
- public func greaterThanOrEqualToSuperview<T: ConstraintRelatableTarget>(_ closure: (ConstraintView) -> T, _ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
- guard let other = self.description.item.superview else {
- fatalError("Expected superview but found nil when attempting make constraint `greaterThanOrEqualToSuperview`.")
- }
- return self.relatedTo(closure(other), relation: .greaterThanOrEqual, file: file, line: line)
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public class ConstraintMakerRelatable {
-
- internal let description: ConstraintDescription
-
- internal init(_ description: ConstraintDescription) {
- self.description = description
- }
-
- internal func relatedTo(_ other: ConstraintRelatableTarget, relation: ConstraintRelation, file: String, line: UInt) -> ConstraintMakerEditable {
- let related: ConstraintItem
- let constant: ConstraintConstantTarget
-
- if let other = other as? ConstraintItem {
- guard other.attributes == ConstraintAttributes.none ||
- other.attributes.layoutAttributes.count <= 1 ||
- other.attributes.layoutAttributes == self.description.attributes.layoutAttributes ||
- other.attributes == .edges && self.description.attributes == .margins ||
- other.attributes == .margins && self.description.attributes == .edges ||
- other.attributes == .directionalEdges && self.description.attributes == .directionalMargins ||
- other.attributes == .directionalMargins && self.description.attributes == .directionalEdges else {
- fatalError("Cannot constraint to multiple non identical attributes. (\(file), \(line))");
- }
-
- related = other
- constant = 0.0
- } else if let other = other as? ConstraintView {
- related = ConstraintItem(target: other, attributes: ConstraintAttributes.none)
- constant = 0.0
- } else if let other = other as? ConstraintConstantTarget {
- related = ConstraintItem(target: nil, attributes: ConstraintAttributes.none)
- constant = other
- } else if #available(iOS 9.0, OSX 10.11, *), let other = other as? ConstraintLayoutGuide {
- related = ConstraintItem(target: other, attributes: ConstraintAttributes.none)
- constant = 0.0
- } else {
- fatalError("Invalid constraint. (\(file), \(line))")
- }
-
- let editable = ConstraintMakerEditable(self.description)
- editable.description.sourceLocation = (file, line)
- editable.description.relation = relation
- editable.description.related = related
- editable.description.constant = constant
- return editable
- }
-
- @discardableResult
- public func equalTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
- return self.relatedTo(other, relation: .equal, file: file, line: line)
- }
-
- @discardableResult
- public func equalToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
- guard let other = self.description.item.superview else {
- fatalError("Expected superview but found nil when attempting make constraint `equalToSuperview`.")
- }
- return self.relatedTo(other, relation: .equal, file: file, line: line)
- }
-
- @discardableResult
- public func lessThanOrEqualTo(_ other: ConstraintRelatableTarget, _ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
- return self.relatedTo(other, relation: .lessThanOrEqual, file: file, line: line)
- }
-
- @discardableResult
- public func lessThanOrEqualToSuperview(_ file: String = #file, _ line: UInt = #line) -> ConstraintMakerEditable {
- guard let other = self.description.item.superview else {
- fatalError("Expected superview but found nil when attempting make constraint `lessThanOrEqualToSuperview`.")
- }
- return self.relatedTo(other, relation: .lessThanOrEqual, file: file, line: line)
- }
-
- @discardableResult
- public func greaterThanOrEqualTo(_ other: ConstraintRelatableTarget, _ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
- return self.relatedTo(other, relation: .greaterThanOrEqual, file: file, line: line)
- }
-
- @discardableResult
- public func greaterThanOrEqualToSuperview(_ file: String = #file, line: UInt = #line) -> ConstraintMakerEditable {
- guard let other = self.description.item.superview else {
- fatalError("Expected superview but found nil when attempting make constraint `greaterThanOrEqualToSuperview`.")
- }
- return self.relatedTo(other, relation: .greaterThanOrEqual, file: file, line: line)
- }
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public protocol ConstraintMultiplierTarget {
-
- var constraintMultiplierTargetValue: CGFloat { get }
-
-}
-
-extension Int: ConstraintMultiplierTarget {
-
- public var constraintMultiplierTargetValue: CGFloat {
- return CGFloat(self)
- }
-
-}
-
-extension UInt: ConstraintMultiplierTarget {
-
- public var constraintMultiplierTargetValue: CGFloat {
- return CGFloat(self)
- }
-
-}
-
-extension Float: ConstraintMultiplierTarget {
-
- public var constraintMultiplierTargetValue: CGFloat {
- return CGFloat(self)
- }
-
-}
-
-extension Double: ConstraintMultiplierTarget {
-
- public var constraintMultiplierTargetValue: CGFloat {
- return CGFloat(self)
- }
-
-}
-
-extension CGFloat: ConstraintMultiplierTarget {
-
- public var constraintMultiplierTargetValue: CGFloat {
- return self
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public protocol ConstraintOffsetTarget: ConstraintConstantTarget {
-}
-
-extension Int: ConstraintOffsetTarget {
-}
-
-extension UInt: ConstraintOffsetTarget {
-}
-
-extension Float: ConstraintOffsetTarget {
-}
-
-extension Double: ConstraintOffsetTarget {
-}
-
-extension CGFloat: ConstraintOffsetTarget {
-}
-
-extension ConstraintOffsetTarget {
-
- internal var constraintOffsetTargetValue: CGFloat {
- let offset: CGFloat
- if let amount = self as? Float {
- offset = CGFloat(amount)
- } else if let amount = self as? Double {
- offset = CGFloat(amount)
- } else if let amount = self as? CGFloat {
- offset = CGFloat(amount)
- } else if let amount = self as? Int {
- offset = CGFloat(amount)
- } else if let amount = self as? UInt {
- offset = CGFloat(amount)
- } else {
- offset = 0.0
- }
- return offset
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-public struct ConstraintPriority : ExpressibleByFloatLiteral, Equatable, Strideable {
- public typealias FloatLiteralType = Float
-
- public let value: Float
-
- public init(floatLiteral value: Float) {
- self.value = value
- }
-
- public init(_ value: Float) {
- self.value = value
- }
-
- public static var required: ConstraintPriority {
- return 1000.0
- }
-
- public static var high: ConstraintPriority {
- return 750.0
- }
-
- public static var medium: ConstraintPriority {
- #if os(OSX)
- return 501.0
- #else
- return 500.0
- #endif
-
- }
-
- public static var low: ConstraintPriority {
- return 250.0
- }
-
- public static func ==(lhs: ConstraintPriority, rhs: ConstraintPriority) -> Bool {
- return lhs.value == rhs.value
- }
-
- // MARK: Strideable
-
- public func advanced(by n: FloatLiteralType) -> ConstraintPriority {
- return ConstraintPriority(floatLiteral: value + n)
- }
-
- public func distance(to other: ConstraintPriority) -> FloatLiteralType {
- return other.value - value
- }
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public protocol ConstraintPriorityTarget {
-
- var constraintPriorityTargetValue: Float { get }
-
-}
-
-extension Int: ConstraintPriorityTarget {
-
- public var constraintPriorityTargetValue: Float {
- return Float(self)
- }
-
-}
-
-extension UInt: ConstraintPriorityTarget {
-
- public var constraintPriorityTargetValue: Float {
- return Float(self)
- }
-
-}
-
-extension Float: ConstraintPriorityTarget {
-
- public var constraintPriorityTargetValue: Float {
- return self
- }
-
-}
-
-extension Double: ConstraintPriorityTarget {
-
- public var constraintPriorityTargetValue: Float {
- return Float(self)
- }
-
-}
-
-extension CGFloat: ConstraintPriorityTarget {
-
- public var constraintPriorityTargetValue: Float {
- return Float(self)
- }
-
-}
-
-#if canImport(UIKit)
-extension UILayoutPriority: ConstraintPriorityTarget {
-
- public var constraintPriorityTargetValue: Float {
- return self.rawValue
- }
-
-}
-#endif
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public protocol ConstraintRelatableTarget {
-}
-
-extension Int: ConstraintRelatableTarget {
-}
-
-extension UInt: ConstraintRelatableTarget {
-}
-
-extension Float: ConstraintRelatableTarget {
-}
-
-extension Double: ConstraintRelatableTarget {
-}
-
-extension CGFloat: ConstraintRelatableTarget {
-}
-
-extension CGSize: ConstraintRelatableTarget {
-}
-
-extension CGPoint: ConstraintRelatableTarget {
-}
-
-extension ConstraintInsets: ConstraintRelatableTarget {
-}
-
-#if canImport(UIKit)
-@available(iOS 11.0, tvOS 11.0, *)
-extension ConstraintDirectionalInsets: ConstraintRelatableTarget {
-}
-#endif
-
-extension ConstraintItem: ConstraintRelatableTarget {
-}
-
-extension ConstraintView: ConstraintRelatableTarget {
-}
-
-@available(iOS 9.0, OSX 10.11, *)
-extension ConstraintLayoutGuide: ConstraintRelatableTarget {
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-internal enum ConstraintRelation : Int {
- case equal = 1
- case lessThanOrEqual
- case greaterThanOrEqual
-
- internal var layoutRelation: LayoutRelation {
- get {
- switch(self) {
- case .equal:
- return .equal
- case .lessThanOrEqual:
- return .lessThanOrEqual
- case .greaterThanOrEqual:
- return .greaterThanOrEqual
- }
- }
- }
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public extension ConstraintView {
-
- @available(*, deprecated, renamed:"snp.left")
- var snp_left: ConstraintItem { return self.snp.left }
-
- @available(*, deprecated, renamed:"snp.top")
- var snp_top: ConstraintItem { return self.snp.top }
-
- @available(*, deprecated, renamed:"snp.right")
- var snp_right: ConstraintItem { return self.snp.right }
-
- @available(*, deprecated, renamed:"snp.bottom")
- var snp_bottom: ConstraintItem { return self.snp.bottom }
-
- @available(*, deprecated, renamed:"snp.leading")
- var snp_leading: ConstraintItem { return self.snp.leading }
-
- @available(*, deprecated, renamed:"snp.trailing")
- var snp_trailing: ConstraintItem { return self.snp.trailing }
-
- @available(*, deprecated, renamed:"snp.width")
- var snp_width: ConstraintItem { return self.snp.width }
-
- @available(*, deprecated, renamed:"snp.height")
- var snp_height: ConstraintItem { return self.snp.height }
-
- @available(*, deprecated, renamed:"snp.centerX")
- var snp_centerX: ConstraintItem { return self.snp.centerX }
-
- @available(*, deprecated, renamed:"snp.centerY")
- var snp_centerY: ConstraintItem { return self.snp.centerY }
-
- @available(*, deprecated, renamed:"snp.baseline")
- var snp_baseline: ConstraintItem { return self.snp.baseline }
-
- @available(*, deprecated, renamed:"snp.lastBaseline")
- @available(iOS 8.0, OSX 10.11, *)
- var snp_lastBaseline: ConstraintItem { return self.snp.lastBaseline }
-
- @available(iOS, deprecated, renamed:"snp.firstBaseline")
- @available(iOS 8.0, OSX 10.11, *)
- var snp_firstBaseline: ConstraintItem { return self.snp.firstBaseline }
-
- @available(iOS, deprecated, renamed:"snp.leftMargin")
- @available(iOS 8.0, *)
- var snp_leftMargin: ConstraintItem { return self.snp.leftMargin }
-
- @available(iOS, deprecated, renamed:"snp.topMargin")
- @available(iOS 8.0, *)
- var snp_topMargin: ConstraintItem { return self.snp.topMargin }
-
- @available(iOS, deprecated, renamed:"snp.rightMargin")
- @available(iOS 8.0, *)
- var snp_rightMargin: ConstraintItem { return self.snp.rightMargin }
-
- @available(iOS, deprecated, renamed:"snp.bottomMargin")
- @available(iOS 8.0, *)
- var snp_bottomMargin: ConstraintItem { return self.snp.bottomMargin }
-
- @available(iOS, deprecated, renamed:"snp.leadingMargin")
- @available(iOS 8.0, *)
- var snp_leadingMargin: ConstraintItem { return self.snp.leadingMargin }
-
- @available(iOS, deprecated, renamed:"snp.trailingMargin")
- @available(iOS 8.0, *)
- var snp_trailingMargin: ConstraintItem { return self.snp.trailingMargin }
-
- @available(iOS, deprecated, renamed:"snp.centerXWithinMargins")
- @available(iOS 8.0, *)
- var snp_centerXWithinMargins: ConstraintItem { return self.snp.centerXWithinMargins }
-
- @available(iOS, deprecated, renamed:"snp.centerYWithinMargins")
- @available(iOS 8.0, *)
- var snp_centerYWithinMargins: ConstraintItem { return self.snp.centerYWithinMargins }
-
- @available(*, deprecated, renamed:"snp.edges")
- var snp_edges: ConstraintItem { return self.snp.edges }
-
- @available(*, deprecated, renamed:"snp.size")
- var snp_size: ConstraintItem { return self.snp.size }
-
- @available(*, deprecated, renamed:"snp.center")
- var snp_center: ConstraintItem { return self.snp.center }
-
- @available(iOS, deprecated, renamed:"snp.margins")
- @available(iOS 8.0, *)
- var snp_margins: ConstraintItem { return self.snp.margins }
-
- @available(iOS, deprecated, renamed:"snp.centerWithinMargins")
- @available(iOS 8.0, *)
- var snp_centerWithinMargins: ConstraintItem { return self.snp.centerWithinMargins }
-
- @available(*, deprecated, renamed:"snp.prepareConstraints(_:)")
- func snp_prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
- return self.snp.prepareConstraints(closure)
- }
-
- @available(*, deprecated, renamed:"snp.makeConstraints(_:)")
- func snp_makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
- self.snp.makeConstraints(closure)
- }
-
- @available(*, deprecated, renamed:"snp.remakeConstraints(_:)")
- func snp_remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
- self.snp.remakeConstraints(closure)
- }
-
- @available(*, deprecated, renamed:"snp.updateConstraints(_:)")
- func snp_updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
- self.snp.updateConstraints(closure)
- }
-
- @available(*, deprecated, renamed:"snp.removeConstraints()")
- func snp_removeConstraints() {
- self.snp.removeConstraints()
- }
-
- var snp: ConstraintViewDSL {
- return ConstraintViewDSL(view: self)
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-#if canImport(UIKit)
- public typealias ConstraintView = UIView
-#else
- public typealias ConstraintView = NSView
-#endif
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public struct ConstraintViewDSL: ConstraintAttributesDSL {
-
- @discardableResult
- public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] {
- return ConstraintMaker.prepareConstraints(item: self.view, closure: closure)
- }
-
- public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
- ConstraintMaker.makeConstraints(item: self.view, closure: closure)
- }
-
- public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
- ConstraintMaker.remakeConstraints(item: self.view, closure: closure)
- }
-
- public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) {
- ConstraintMaker.updateConstraints(item: self.view, closure: closure)
- }
-
- public func removeConstraints() {
- ConstraintMaker.removeConstraints(item: self.view)
- }
-
- public var contentHuggingHorizontalPriority: Float {
- get {
- return self.view.contentHuggingPriority(for: .horizontal).rawValue
- }
- nonmutating set {
- self.view.setContentHuggingPriority(LayoutPriority(rawValue: newValue), for: .horizontal)
- }
- }
-
- public var contentHuggingVerticalPriority: Float {
- get {
- return self.view.contentHuggingPriority(for: .vertical).rawValue
- }
- nonmutating set {
- self.view.setContentHuggingPriority(LayoutPriority(rawValue: newValue), for: .vertical)
- }
- }
-
- public var contentCompressionResistanceHorizontalPriority: Float {
- get {
- return self.view.contentCompressionResistancePriority(for: .horizontal).rawValue
- }
- nonmutating set {
- self.view.setContentCompressionResistancePriority(LayoutPriority(rawValue: newValue), for: .horizontal)
- }
- }
-
- public var contentCompressionResistanceVerticalPriority: Float {
- get {
- return self.view.contentCompressionResistancePriority(for: .vertical).rawValue
- }
- nonmutating set {
- self.view.setContentCompressionResistancePriority(LayoutPriority(rawValue: newValue), for: .vertical)
- }
- }
-
- public var target: AnyObject? {
- return self.view
- }
-
- internal let view: ConstraintView
-
- internal init(view: ConstraintView) {
- self.view = view
-
- }
-
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-public extension LayoutConstraint {
-
- override var description: String {
- var description = "<"
-
- description += descriptionForObject(self)
-
- if let firstItem = conditionalOptional(from: self.firstItem) {
- description += " \(descriptionForObject(firstItem))"
- }
-
- if self.firstAttribute != .notAnAttribute {
- description += ".\(descriptionForAttribute(self.firstAttribute))"
- }
-
- description += " \(descriptionForRelation(self.relation))"
-
- if let secondItem = self.secondItem {
- description += " \(descriptionForObject(secondItem))"
- }
-
- if self.secondAttribute != .notAnAttribute {
- description += ".\(descriptionForAttribute(self.secondAttribute))"
- }
-
- if self.multiplier != 1.0 {
- description += " * \(self.multiplier)"
- }
-
- if self.secondAttribute == .notAnAttribute {
- description += " \(self.constant)"
- } else {
- if self.constant > 0.0 {
- description += " + \(self.constant)"
- } else if self.constant < 0.0 {
- description += " - \(abs(self.constant))"
- }
- }
-
- if self.priority.rawValue != 1000.0 {
- description += " ^\(self.priority)"
- }
-
- description += ">"
-
- return description
- }
-
-}
-
-private func descriptionForRelation(_ relation: LayoutRelation) -> String {
- switch relation {
- case .equal: return "=="
- case .greaterThanOrEqual: return ">="
- case .lessThanOrEqual: return "<="
- #if swift(>=5.0)
- @unknown default: return "unknown"
- #endif
- }
-}
-
-private func descriptionForAttribute(_ attribute: LayoutAttribute) -> String {
- #if canImport(UIKit)
- switch attribute {
- case .notAnAttribute: return "notAnAttribute"
- case .top: return "top"
- case .left: return "left"
- case .bottom: return "bottom"
- case .right: return "right"
- case .leading: return "leading"
- case .trailing: return "trailing"
- case .width: return "width"
- case .height: return "height"
- case .centerX: return "centerX"
- case .centerY: return "centerY"
- case .lastBaseline: return "lastBaseline"
- case .firstBaseline: return "firstBaseline"
- case .topMargin: return "topMargin"
- case .leftMargin: return "leftMargin"
- case .bottomMargin: return "bottomMargin"
- case .rightMargin: return "rightMargin"
- case .leadingMargin: return "leadingMargin"
- case .trailingMargin: return "trailingMargin"
- case .centerXWithinMargins: return "centerXWithinMargins"
- case .centerYWithinMargins: return "centerYWithinMargins"
- #if swift(>=5.0)
- @unknown default: return "unknown"
- #endif
- }
- #else
- switch attribute {
- case .notAnAttribute: return "notAnAttribute"
- case .top: return "top"
- case .left: return "left"
- case .bottom: return "bottom"
- case .right: return "right"
- case .leading: return "leading"
- case .trailing: return "trailing"
- case .width: return "width"
- case .height: return "height"
- case .centerX: return "centerX"
- case .centerY: return "centerY"
- case .lastBaseline: return "lastBaseline"
- case .firstBaseline: return "firstBaseline"
- #if swift(>=5.0)
- @unknown default: return "unknown"
- #endif
- }
- #endif
-}
-
-private func conditionalOptional<T>(from object: Optional<T>) -> Optional<T> {
- return object
-}
-
-private func conditionalOptional<T>(from object: T) -> Optional<T> {
- return Optional.some(object)
-}
-
-private func descriptionForObject(_ object: AnyObject) -> String {
- let pointerDescription = String(format: "%p", UInt(bitPattern: ObjectIdentifier(object)))
- var desc = ""
-
- desc += type(of: object).description()
-
- if let object = object as? ConstraintView {
- desc += ":\(object.snp.label() ?? pointerDescription)"
- } else if let object = object as? LayoutConstraint {
- desc += ":\(object.label ?? pointerDescription)"
- } else {
- desc += ":\(pointerDescription)"
- }
-
- if let object = object as? LayoutConstraint, let file = object.constraint?.sourceLocation.0, let line = object.constraint?.sourceLocation.1 {
- desc += "@\((file as NSString).lastPathComponent)#\(line)"
- }
-
- desc += ""
- return desc
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public class LayoutConstraint : NSLayoutConstraint {
-
- public var label: String? {
- get {
- return self.identifier
- }
- set {
- self.identifier = newValue
- }
- }
-
- internal weak var constraint: Constraint? = nil
-
-}
-
-internal func ==(lhs: LayoutConstraint, rhs: LayoutConstraint) -> Bool {
- // If firstItem or secondItem on either constraint has a dangling pointer
- // this comparison can cause a crash. The solution for this is to ensure
- // your layout code hold strong references to things like Views, LayoutGuides
- // and LayoutAnchors as SnapKit will not keep strong references to any of these.
- guard lhs.firstAttribute == rhs.firstAttribute &&
- lhs.secondAttribute == rhs.secondAttribute &&
- lhs.relation == rhs.relation &&
- lhs.priority == rhs.priority &&
- lhs.multiplier == rhs.multiplier &&
- lhs.secondItem === rhs.secondItem &&
- lhs.firstItem === rhs.firstItem else {
- return false
- }
- return true
-}
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#else
- import AppKit
-#endif
-
-
-public protocol LayoutConstraintItem: AnyObject {
-}
-
-@available(iOS 9.0, OSX 10.11, *)
-extension ConstraintLayoutGuide : LayoutConstraintItem {
-}
-
-extension ConstraintView : LayoutConstraintItem {
-}
-
-
-extension LayoutConstraintItem {
-
- internal func prepare() {
- if let view = self as? ConstraintView {
- view.translatesAutoresizingMaskIntoConstraints = false
- }
- }
-
- internal var superview: ConstraintView? {
- if let view = self as? ConstraintView {
- return view.superview
- }
-
- if #available(iOS 9.0, OSX 10.11, *), let guide = self as? ConstraintLayoutGuide {
- return guide.owningView
- }
-
- return nil
- }
- internal var constraints: [Constraint] {
- return self.constraintsSet.allObjects as! [Constraint]
- }
-
- internal func add(constraints: [Constraint]) {
- let constraintsSet = self.constraintsSet
- for constraint in constraints {
- constraintsSet.add(constraint)
- }
- }
-
- internal func remove(constraints: [Constraint]) {
- let constraintsSet = self.constraintsSet
- for constraint in constraints {
- constraintsSet.remove(constraint)
- }
- }
-
- private var constraintsSet: NSMutableSet {
- let constraintsSet: NSMutableSet
-
- if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSMutableSet {
- constraintsSet = existing
- } else {
- constraintsSet = NSMutableSet()
- objc_setAssociatedObject(self, &constraintsKey, constraintsSet, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
- }
- return constraintsSet
-
- }
-
-}
-private var constraintsKey: UInt8 = 0
+++ /dev/null
-<?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>NSPrivacyTracking</key>
- <false/>
- <key>NSPrivacyAccessedAPITypes</key>
- <array/>
- <key>NSPrivacyCollectedDataTypes</key>
- <array/>
- <key>NSPrivacyTrackingDomains</key>
- <array/>
-</dict>
-</plist>
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-import Foundation
-
-#if canImport(UIKit)
- import UIKit
-#if swift(>=4.2)
- typealias LayoutRelation = NSLayoutConstraint.Relation
- typealias LayoutAttribute = NSLayoutConstraint.Attribute
-#else
- typealias LayoutRelation = NSLayoutRelation
- typealias LayoutAttribute = NSLayoutAttribute
-#endif
- typealias LayoutPriority = UILayoutPriority
-#else
- import AppKit
- typealias LayoutRelation = NSLayoutConstraint.Relation
- typealias LayoutAttribute = NSLayoutConstraint.Attribute
- typealias LayoutPriority = NSLayoutConstraint.Priority
-#endif
-
+++ /dev/null
-//
-// SnapKit
-//
-// Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if canImport(UIKit)
- import UIKit
-#endif
-
-
-@available(iOS 8.0, *)
-public extension ConstraintLayoutSupport {
-
- var snp: ConstraintLayoutSupportDSL {
- return ConstraintLayoutSupportDSL(support: self)
- }
-
-}
+++ /dev/null
-BSD License
-
-For SocketRocket software
-
-Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- * Neither the name Facebook nor the names of its contributors may be used to
- endorse or promote products derived from this software without specific
- prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
+++ /dev/null
-Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
-
-The examples provided by Facebook are for non-commercial testing and evaluation
-purposes only. Facebook reserves all rights not expressly granted.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+++ /dev/null
-# SocketRocket
-
-![Platforms][platforms-svg]
-[![License][license-svg]][license-link]
-
-[![Podspec][podspec-svg]][podspec-link]
-[![Carthage Compatible][carthage-svg]](carthage-link)
-
-[![Build Status][build-status-svg]][build-status-link]
-
-A conforming WebSocket ([RFC 6455](https://tools.ietf.org/html/rfc6455>)) client library for iOS, macOS and tvOS.
-
-Test results for SocketRocket [here](http://facebook.github.io/SocketRocket/results/).
-You can compare to what modern browsers look like [here](http://autobahn.ws/testsuite/reports/clients/index.html).
-
-SocketRocket currently conforms to all core ~300 of [Autobahn](http://autobahn.ws/testsuite/>)'s fuzzing tests
-(aside from two UTF-8 ones where it is merely *non-strict* tests 6.4.2 and 6.4.4).
-
-## Features/Design
-
-- TLS (wss) support, including self-signed certificates.
-- Seems to perform quite well.
-- Supports HTTP Proxies.
-- Supports IPv4/IPv6.
-- Supports SSL certificate pinning.
-- Sends `ping` and can process `pong` events.
-- Asynchronous and non-blocking. Most of the work is done on a background thread.
-- Supports iOS, macOS, tvOS.
-
-## Installing
-
-There are a few options. Choose one, or just figure it out:
-
-- **[CocoaPods](https://cocoapods.org)**
-
- Add the following line to your Podfile:
- ```ruby
- pod 'SocketRocket'
- ```
- Run `pod install`, and you are all set.
-
-- **[Carthage](https://github.com/carthage/carthage)**
-
- Add the following line to your Cartfile:
- ```
- github "facebook/SocketRocket"
- ```
- Run `carthage update`, and you should now have the latest version of `SocketRocket` in your `Carthage` folder.
-
-- **Using SocketRocket as a sub-project**
-
- You can also include `SocketRocket` as a subproject inside of your application if you'd prefer, although we do not recommend this, as it will increase your indexing time significantly. To do so, just drag and drop the `SocketRocket.xcodeproj` file into your workspace.
-
-## API
-
-### `SRWebSocket`
-
-The Web Socket.
-
-#### Note:
-
-`SRWebSocket` will retain itself between `-(void)open` and when it closes, errors, or fails.
-This is similar to how `NSURLConnection` behaves (unlike `NSURLConnection`, `SRWebSocket` won't retain the delegate).
-
-#### Interface
-
-```objective-c
-@interface SRWebSocket : NSObject
-
-// Make it with this
-- (instancetype)initWithURLRequest:(NSURLRequest *)request;
-
-// Set this before opening
-@property (nonatomic, weak) id <SRWebSocketDelegate> delegate;
-
-// Open with this
-- (void)open;
-
-// Close it with this
-- (void)close;
-
-// Send a Data
-- (void)sendData:(nullable NSData *)data error:(NSError **)error;
-
-// Send a UTF8 String
-- (void)sendString:(NSString *)string error:(NSError **)error;
-
-@end
-```
-
-### `SRWebSocketDelegate`
-
-You implement this
-
-```objective-c
-@protocol SRWebSocketDelegate <NSObject>
-
-@optional
-
-- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
-
-- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithString:(NSString *)string;
-- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithData:(NSData *)data;
-
-- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
-- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(nullable NSString *)reason wasClean:(BOOL)wasClean;
-
-@end
-```
-
-## Testing
-
-Included are setup scripts for the python testing environment.
-It comes packaged with vitualenv so all the dependencies are installed in userland.
-
-To run the short test from the command line, run:
-```bash
- make test
-```
-
-To run all the tests, run:
-```bash
- make test_all
-```
-
-The short tests don't include the performance tests
-(the test harness is actually the bottleneck, not SocketRocket).
-
-The first time this is run, it may take a while to install the dependencies. It will be smooth sailing after that.
-
-You can also run tests inside Xcode, which runs the same thing, but makes it easier to debug.
-
-- Choose the `SocketRocketTests` target
-- Make sure your running destination is either your Mac or any Simulator
-- Run the test action (`⌘+U`)
-
-### TestChat Demo Application
-
-SocketRocket includes a demo app, TestChat.
-It will "chat" with a listening websocket on port 9900.
-
-#### TestChat Server
-
-The sever takes a message and broadcasts it to all other connected clients.
-
-It requires some dependencies though to run.
-We also want to reuse the virtualenv we made when we ran the tests.
-If you haven't run the tests yet, go into the SocketRocket root directory and type:
-
-```bash
-make test
-```
-
-This will set up your [virtualenv](https://pypi.python.org/pypi/virtualenv).
-
-Now, in your terminal:
-
-```bash
-source .env/bin/activate
-pip install git+https://github.com/tornadoweb/tornado.git
-```
-
-In the same terminal session, start the chatroom server:
-
-```bash
-python TestChatServer/py/chatroom.py
-```
-
-There's also a Go implementation (with the latest weekly) where you can:
-
-```bash
-cd TestChatServer/go
-go run chatroom.go
-```
-
-#### Chatting
-
-Now, start TestChat.app (just run the target in the Xcode project).
-If you had it started already you can hit the refresh button to reconnect.
-It should say "Connected!" on top.
-
-To talk with the app, open up your browser to [http://localhost:9000](http://localhost:9000) and start chatting.
-
-
-## WebSocket Server Implementation Recommendations
-
-SocketRocket has been used with the following libraries:
-
-- [Tornado](https://github.com/tornadoweb/tornado)
-- Go's [WebSocket package](https://godoc.org/golang.org/x/net/websocket) or Gorilla's [version](http://www.gorillatoolkit.org/pkg/websocket).
-- [Autobahn](http://autobahn.ws/testsuite/) (using its fuzzing client).
-
-The Tornado one is dirt simple and works like a charm.
-([IPython notebook](http://ipython.org/ipython-doc/dev/interactive/htmlnotebook.html) uses it too).
-It's much easier to configure handlers and routes than in Autobahn/twisted.
-
-## Contributing
-
-We’re glad you’re interested in SocketRocket, and we’d love to see where you take it.
-Please read our [contributing guidelines](https://github.com/facebook/SocketRocket/blob/master/CONTRIBUTING.md) prior to submitting a Pull Request.
-
- [build-status-svg]: https://img.shields.io/travis/facebook/SocketRocket/master.svg
- [build-status-link]: https://travis-ci.org/facebook/SocketRocket/branches
-
- [license-svg]: https://img.shields.io/badge/license-BSD-lightgrey.svg
- [license-link]: https://github.com/facebook/SocketRocket/blob/master/LICENSE
-
- [podspec-svg]: https://img.shields.io/cocoapods/v/SocketRocket.svg
- [podspec-link]: https://cocoapods.org/pods/SocketRocket
-
- [carthage-svg]: https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat
- [carthage-link]: https://github.com/carthage/carthage
-
- [platforms-svg]: http://img.shields.io/cocoapods/p/SocketRocket.svg?style=flat
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-#import <SocketRocket/SRWebSocket.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-#if OBJC_BOOL_IS_BOOL
-
-struct SRDelegateAvailableMethods {
- BOOL didReceiveMessage : 1;
- BOOL didReceiveMessageWithString : 1;
- BOOL didReceiveMessageWithData : 1;
- BOOL didOpen : 1;
- BOOL didFailWithError : 1;
- BOOL didCloseWithCode : 1;
- BOOL didReceivePing : 1;
- BOOL didReceivePong : 1;
- BOOL shouldConvertTextFrameToString : 1;
-};
-
-#else
-
-struct SRDelegateAvailableMethods {
- BOOL didReceiveMessage;
- BOOL didReceiveMessageWithString;
- BOOL didReceiveMessageWithData;
- BOOL didOpen;
- BOOL didFailWithError;
- BOOL didCloseWithCode;
- BOOL didReceivePing;
- BOOL didReceivePong;
- BOOL shouldConvertTextFrameToString;
-};
-
-#endif
-
-typedef struct SRDelegateAvailableMethods SRDelegateAvailableMethods;
-
-typedef void(^SRDelegateBlock)(id<SRWebSocketDelegate> _Nullable delegate, SRDelegateAvailableMethods availableMethods);
-
-@interface SRDelegateController : NSObject
-
-@property (nonatomic, weak) id<SRWebSocketDelegate> delegate;
-@property (atomic, readonly) SRDelegateAvailableMethods availableDelegateMethods;
-
-@property (nullable, nonatomic, strong) dispatch_queue_t dispatchQueue;
-@property (nullable, nonatomic, strong) NSOperationQueue *operationQueue;
-
-///--------------------------------------
-#pragma mark - Perform
-///--------------------------------------
-
-- (void)performDelegateBlock:(SRDelegateBlock)block;
-- (void)performDelegateQueueBlock:(dispatch_block_t)block;
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRDelegateController.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface SRDelegateController ()
-
-@property (nonatomic, strong, readonly) dispatch_queue_t accessQueue;
-
-@property (atomic, assign, readwrite) SRDelegateAvailableMethods availableDelegateMethods;
-
-@end
-
-@implementation SRDelegateController
-
-@synthesize delegate = _delegate;
-@synthesize dispatchQueue = _dispatchQueue;
-@synthesize operationQueue = _operationQueue;
-
-///--------------------------------------
-#pragma mark - Init
-///--------------------------------------
-
-- (instancetype)init
-{
- self = [super init];
- if (!self) return self;
-
- _accessQueue = dispatch_queue_create("com.facebook.socketrocket.delegate.access", DISPATCH_QUEUE_CONCURRENT);
- _dispatchQueue = dispatch_get_main_queue();
-
- return self;
-}
-
-///--------------------------------------
-#pragma mark - Accessors
-///--------------------------------------
-
-- (void)setDelegate:(id<SRWebSocketDelegate> _Nullable)delegate
-{
- dispatch_barrier_async(self.accessQueue, ^{
- self->_delegate = delegate;
-
- self.availableDelegateMethods = (SRDelegateAvailableMethods){
- .didReceiveMessage = [delegate respondsToSelector:@selector(webSocket:didReceiveMessage:)],
- .didReceiveMessageWithString = [delegate respondsToSelector:@selector(webSocket:didReceiveMessageWithString:)],
- .didReceiveMessageWithData = [delegate respondsToSelector:@selector(webSocket:didReceiveMessageWithData:)],
- .didOpen = [delegate respondsToSelector:@selector(webSocketDidOpen:)],
- .didFailWithError = [delegate respondsToSelector:@selector(webSocket:didFailWithError:)],
- .didCloseWithCode = [delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)],
- .didReceivePing = [delegate respondsToSelector:@selector(webSocket:didReceivePingWithData:)],
- .didReceivePong = [delegate respondsToSelector:@selector(webSocket:didReceivePong:)],
- .shouldConvertTextFrameToString = [delegate respondsToSelector:@selector(webSocketShouldConvertTextFrameToString:)]
- };
- });
-}
-
-- (id<SRWebSocketDelegate> _Nullable)delegate
-{
- __block id<SRWebSocketDelegate> delegate = nil;
- dispatch_sync(self.accessQueue, ^{
- delegate = self->_delegate;
- });
- return delegate;
-}
-
-- (void)setDispatchQueue:(dispatch_queue_t _Nullable)queue
-{
- dispatch_barrier_async(self.accessQueue, ^{
- self->_dispatchQueue = queue ?: dispatch_get_main_queue();
- self->_operationQueue = nil;
- });
-}
-
-- (dispatch_queue_t _Nullable)dispatchQueue
-{
- __block dispatch_queue_t queue = nil;
- dispatch_sync(self.accessQueue, ^{
- queue = self->_dispatchQueue;
- });
- return queue;
-}
-
-- (void)setOperationQueue:(NSOperationQueue *_Nullable)queue
-{
- dispatch_barrier_async(self.accessQueue, ^{
- self->_dispatchQueue = queue ? nil : dispatch_get_main_queue();
- self->_operationQueue = queue;
- });
-}
-
-- (NSOperationQueue *_Nullable)operationQueue
-{
- __block NSOperationQueue *queue = nil;
- dispatch_sync(self.accessQueue, ^{
- queue = self->_operationQueue;
- });
- return queue;
-}
-
-///--------------------------------------
-#pragma mark - Perform
-///--------------------------------------
-
-- (void)performDelegateBlock:(SRDelegateBlock)block
-{
- __block __strong id<SRWebSocketDelegate> delegate = nil;
- __block SRDelegateAvailableMethods availableMethods;
- dispatch_sync(self.accessQueue, ^{
- delegate = self->_delegate; // Not `OK` to go through `self`, since queue sync.
- availableMethods = self.availableDelegateMethods; // `OK` to call through `self`, since no queue sync.
- });
- [self performDelegateQueueBlock:^{
- block(delegate, availableMethods);
- }];
-}
-
-- (void)performDelegateQueueBlock:(dispatch_block_t)block
-{
- dispatch_queue_t dispatchQueue = self.dispatchQueue;
- if (dispatchQueue) {
- dispatch_async(dispatchQueue, block);
- } else {
- [self.operationQueue addOperationWithBlock:block];
- }
-}
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-@class SRWebSocket; // TODO: (nlutsenko) Remove dependency on SRWebSocket here.
-
-// Returns number of bytes consumed. Returning 0 means you didn't match.
-// Sends bytes to callback handler;
-typedef size_t (^stream_scanner)(NSData *collected_data);
-typedef void (^data_callback)(SRWebSocket *webSocket, NSData *data);
-
-@interface SRIOConsumer : NSObject {
- stream_scanner _scanner;
- data_callback _handler;
- size_t _bytesNeeded;
- BOOL _readToCurrentFrame;
- BOOL _unmaskBytes;
-}
-@property (nonatomic, copy, readonly) stream_scanner consumer;
-@property (nonatomic, copy, readonly) data_callback handler;
-@property (nonatomic, assign) size_t bytesNeeded;
-@property (nonatomic, assign, readonly) BOOL readToCurrentFrame;
-@property (nonatomic, assign, readonly) BOOL unmaskBytes;
-
-- (void)resetWithScanner:(stream_scanner)scanner
- handler:(data_callback)handler
- bytesNeeded:(size_t)bytesNeeded
- readToCurrentFrame:(BOOL)readToCurrentFrame
- unmaskBytes:(BOOL)unmaskBytes;
-
-@end
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRIOConsumer.h"
-
-@implementation SRIOConsumer
-
-@synthesize bytesNeeded = _bytesNeeded;
-@synthesize consumer = _scanner;
-@synthesize handler = _handler;
-@synthesize readToCurrentFrame = _readToCurrentFrame;
-@synthesize unmaskBytes = _unmaskBytes;
-
-- (void)resetWithScanner:(stream_scanner)scanner
- handler:(data_callback)handler
- bytesNeeded:(size_t)bytesNeeded
- readToCurrentFrame:(BOOL)readToCurrentFrame
- unmaskBytes:(BOOL)unmaskBytes
-{
- _scanner = [scanner copy];
- _handler = [handler copy];
- _bytesNeeded = bytesNeeded;
- _readToCurrentFrame = readToCurrentFrame;
- _unmaskBytes = unmaskBytes;
- assert(_scanner || _bytesNeeded);
-}
-
-@end
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-#import "SRIOConsumer.h" // TODO: (nlutsenko) Convert to @class and constants file for block types
-
-// This class is not thread-safe, and is expected to always be run on the same queue.
-@interface SRIOConsumerPool : NSObject
-
-- (instancetype)initWithBufferCapacity:(NSUInteger)poolSize;
-
-- (SRIOConsumer *)consumerWithScanner:(stream_scanner)scanner
- handler:(data_callback)handler
- bytesNeeded:(size_t)bytesNeeded
- readToCurrentFrame:(BOOL)readToCurrentFrame
- unmaskBytes:(BOOL)unmaskBytes;
-- (void)returnConsumer:(SRIOConsumer *)consumer;
-
-@end
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRIOConsumerPool.h"
-
-@implementation SRIOConsumerPool {
- NSUInteger _poolSize;
- NSMutableArray<SRIOConsumer *> *_bufferedConsumers;
-}
-
-- (instancetype)initWithBufferCapacity:(NSUInteger)poolSize
-{
- self = [super init];
- if (self) {
- _poolSize = poolSize;
- _bufferedConsumers = [NSMutableArray arrayWithCapacity:poolSize];
- }
- return self;
-}
-
-- (instancetype)init
-{
- return [self initWithBufferCapacity:8];
-}
-
-- (SRIOConsumer *)consumerWithScanner:(stream_scanner)scanner
- handler:(data_callback)handler
- bytesNeeded:(size_t)bytesNeeded
- readToCurrentFrame:(BOOL)readToCurrentFrame
- unmaskBytes:(BOOL)unmaskBytes
-{
- SRIOConsumer *consumer = nil;
- if (_bufferedConsumers.count) {
- consumer = [_bufferedConsumers lastObject];
- [_bufferedConsumers removeLastObject];
- } else {
- consumer = [[SRIOConsumer alloc] init];
- }
-
- [consumer resetWithScanner:scanner
- handler:handler
- bytesNeeded:bytesNeeded
- readToCurrentFrame:readToCurrentFrame
- unmaskBytes:unmaskBytes];
-
- return consumer;
-}
-
-- (void)returnConsumer:(SRIOConsumer *)consumer
-{
- if (_bufferedConsumers.count < _poolSize) {
- [_bufferedConsumers addObject:consumer];
- }
-}
-
-@end
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <SocketRocket/NSRunLoop+SRWebSocket.h>
-
-// Empty function that force links the object file for the category.
-extern void import_NSRunLoop_SRWebSocket(void);
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <SocketRocket/NSURLRequest+SRWebSocket.h>
-
-// Empty function that force links the object file for the category.
-extern void import_NSURLRequest_SRWebSocket(void);
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-typedef void(^SRProxyConnectCompletion)(NSError *_Nullable error,
- NSInputStream *_Nullable readStream,
- NSOutputStream *_Nullable writeStream);
-
-@interface SRProxyConnect : NSObject
-
-- (instancetype)initWithURL:(NSURL *)url;
-
-- (void)openNetworkStreamWithCompletion:(SRProxyConnectCompletion)completion;
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRProxyConnect.h"
-
-#import "NSRunLoop+SRWebSocket.h"
-#import "SRConstants.h"
-#import "SRError.h"
-#import "SRLog.h"
-#import "SRURLUtilities.h"
-
-@interface SRProxyConnect() <NSStreamDelegate>
-
-@property (nonatomic, strong) NSURL *url;
-@property (nonatomic, strong) NSInputStream *inputStream;
-@property (nonatomic, strong) NSOutputStream *outputStream;
-
-@end
-
-@implementation SRProxyConnect
-{
- SRProxyConnectCompletion _completion;
-
- NSString *_httpProxyHost;
- uint32_t _httpProxyPort;
-
- CFHTTPMessageRef _receivedHTTPHeaders;
-
- NSString *_socksProxyHost;
- uint32_t _socksProxyPort;
- NSString *_socksProxyUsername;
- NSString *_socksProxyPassword;
-
- BOOL _connectionRequiresSSL;
-
- NSMutableArray<NSData *> *_inputQueue;
- dispatch_queue_t _writeQueue;
-}
-
-///--------------------------------------
-#pragma mark - Init
-///--------------------------------------
-
--(instancetype)initWithURL:(NSURL *)url
-{
- self = [super init];
- if (!self) return self;
-
- _url = url;
- _connectionRequiresSSL = SRURLRequiresSSL(url);
-
- _writeQueue = dispatch_queue_create("com.facebook.socketrocket.proxyconnect.write", DISPATCH_QUEUE_SERIAL);
- _inputQueue = [NSMutableArray arrayWithCapacity:2];
-
- return self;
-}
-
-- (void)dealloc
-{
- // If we get deallocated before the socket open finishes - we need to cleanup everything.
-
- [self.inputStream removeFromRunLoop:[NSRunLoop SR_networkRunLoop] forMode:NSDefaultRunLoopMode];
- self.inputStream.delegate = nil;
- [self.inputStream close];
- self.inputStream = nil;
-
- self.outputStream.delegate = nil;
- [self.outputStream close];
- self.outputStream = nil;
-}
-
-///--------------------------------------
-#pragma mark - Open
-///--------------------------------------
-
-- (void)openNetworkStreamWithCompletion:(SRProxyConnectCompletion)completion
-{
- _completion = completion;
- [self _configureProxy];
-}
-
-///--------------------------------------
-#pragma mark - Flow
-///--------------------------------------
-
-- (void)_didConnect
-{
- SRDebugLog(@"_didConnect, return streams");
- if (_connectionRequiresSSL) {
- if (_httpProxyHost) {
- // Must set the real peer name before turning on SSL
- SRDebugLog(@"proxy set peer name to real host %@", self.url.host);
- [self.outputStream setProperty:self.url.host forKey:@"_kCFStreamPropertySocketPeerName"];
- }
- }
- if (_receivedHTTPHeaders) {
- CFRelease(_receivedHTTPHeaders);
- _receivedHTTPHeaders = NULL;
- }
-
- NSInputStream *inputStream = self.inputStream;
- NSOutputStream *outputStream = self.outputStream;
-
- self.inputStream = nil;
- self.outputStream = nil;
-
- [inputStream removeFromRunLoop:[NSRunLoop SR_networkRunLoop] forMode:NSDefaultRunLoopMode];
- inputStream.delegate = nil;
- outputStream.delegate = nil;
-
- _completion(nil, inputStream, outputStream);
-}
-
-- (void)_failWithError:(NSError *)error
-{
- SRDebugLog(@"_failWithError, return error");
- if (!error) {
- error = SRHTTPErrorWithCodeDescription(500, 2132,@"Proxy Error");
- }
-
- if (_receivedHTTPHeaders) {
- CFRelease(_receivedHTTPHeaders);
- _receivedHTTPHeaders = NULL;
- }
-
- self.inputStream.delegate = nil;
- self.outputStream.delegate = nil;
-
- [self.inputStream removeFromRunLoop:[NSRunLoop SR_networkRunLoop]
- forMode:NSDefaultRunLoopMode];
- [self.inputStream close];
- [self.outputStream close];
- self.inputStream = nil;
- self.outputStream = nil;
- _completion(error, nil, nil);
-}
-
-// get proxy setting from device setting
-- (void)_configureProxy
-{
- SRDebugLog(@"configureProxy");
- NSDictionary *proxySettings = CFBridgingRelease(CFNetworkCopySystemProxySettings());
-
- // CFNetworkCopyProxiesForURL doesn't understand ws:// or wss://
- NSURL *httpURL;
- if (_connectionRequiresSSL) {
- httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", _url.host]];
- } else {
- httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", _url.host]];
- }
-
- NSArray *proxies = CFBridgingRelease(CFNetworkCopyProxiesForURL((__bridge CFURLRef)httpURL, (__bridge CFDictionaryRef)proxySettings));
- if (proxies.count == 0) {
- SRDebugLog(@"configureProxy no proxies");
- [self _openConnection];
- return; // no proxy
- }
- NSDictionary *settings = [proxies objectAtIndex:0];
- NSString *proxyType = settings[(NSString *)kCFProxyTypeKey];
- if ([proxyType isEqualToString:(NSString *)kCFProxyTypeAutoConfigurationURL]) {
- NSURL *pacURL = settings[(NSString *)kCFProxyAutoConfigurationURLKey];
- if (pacURL) {
- [self _fetchPAC:pacURL withProxySettings:proxySettings];
- return;
- }
- }
- if ([proxyType isEqualToString:(__bridge NSString *)kCFProxyTypeAutoConfigurationJavaScript]) {
- NSString *script = settings[(__bridge NSString *)kCFProxyAutoConfigurationJavaScriptKey];
- if (script) {
- [self _runPACScript:script withProxySettings:proxySettings];
- return;
- }
- }
- [self _readProxySettingWithType:proxyType settings:settings];
-
- [self _openConnection];
-}
-
-- (void)_readProxySettingWithType:(NSString *)proxyType settings:(NSDictionary *)settings
-{
- if ([proxyType isEqualToString:(NSString *)kCFProxyTypeHTTP] ||
- [proxyType isEqualToString:(NSString *)kCFProxyTypeHTTPS]) {
- _httpProxyHost = settings[(NSString *)kCFProxyHostNameKey];
- NSNumber *portValue = settings[(NSString *)kCFProxyPortNumberKey];
- if (portValue) {
- _httpProxyPort = [portValue intValue];
- }
- }
- if ([proxyType isEqualToString:(NSString *)kCFProxyTypeSOCKS]) {
- _socksProxyHost = settings[(NSString *)kCFProxyHostNameKey];
- NSNumber *portValue = settings[(NSString *)kCFProxyPortNumberKey];
- if (portValue)
- _socksProxyPort = [portValue intValue];
- _socksProxyUsername = settings[(NSString *)kCFProxyUsernameKey];
- _socksProxyPassword = settings[(NSString *)kCFProxyPasswordKey];
- }
- if (_httpProxyHost) {
- SRDebugLog(@"Using http proxy %@:%u", _httpProxyHost, _httpProxyPort);
- } else if (_socksProxyHost) {
- SRDebugLog(@"Using socks proxy %@:%u", _socksProxyHost, _socksProxyPort);
- } else {
- SRDebugLog(@"configureProxy no proxies");
- }
-}
-
-- (void)_fetchPAC:(NSURL *)PACurl withProxySettings:(NSDictionary *)proxySettings
-{
- SRDebugLog(@"SRWebSocket fetchPAC:%@", PACurl);
-
- if ([PACurl isFileURL]) {
- NSError *error = nil;
- NSString *script = [NSString stringWithContentsOfURL:PACurl
- usedEncoding:NULL
- error:&error];
-
- if (error) {
- [self _openConnection];
- } else {
- [self _runPACScript:script withProxySettings:proxySettings];
- }
- return;
- }
-
- NSString *scheme = [PACurl.scheme lowercaseString];
- if (![scheme isEqualToString:@"http"] && ![scheme isEqualToString:@"https"]) {
- // Don't know how to read data from this URL, we'll have to give up
- // We'll simply assume no proxies, and start the request as normal
- [self _openConnection];
- return;
- }
- __weak typeof(self) wself = self;
- NSURLRequest *request = [NSURLRequest requestWithURL:PACurl];
- NSURLSession *session = [NSURLSession sharedSession];
- [[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
- __strong typeof(wself) sself = wself;
- if (!error) {
- NSString *script = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
- [sself _runPACScript:script withProxySettings:proxySettings];
- } else {
- [sself _openConnection];
- }
- }] resume];
-}
-
-- (void)_runPACScript:(NSString *)script withProxySettings:(NSDictionary *)proxySettings
-{
- if (!script) {
- [self _openConnection];
- return;
- }
- SRDebugLog(@"runPACScript");
- // From: http://developer.apple.com/samplecode/CFProxySupportTool/listing1.html
- // Work around <rdar://problem/5530166>. This dummy call to
- // CFNetworkCopyProxiesForURL initialise some state within CFNetwork
- // that is required by CFNetworkCopyProxiesForAutoConfigurationScript.
- CFBridgingRelease(CFNetworkCopyProxiesForURL((__bridge CFURLRef)_url, (__bridge CFDictionaryRef)proxySettings));
-
- // Obtain the list of proxies by running the autoconfiguration script
- CFErrorRef err = NULL;
-
- // CFNetworkCopyProxiesForAutoConfigurationScript doesn't understand ws:// or wss://
- NSURL *httpURL;
- if (_connectionRequiresSSL)
- httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", _url.host]];
- else
- httpURL = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@", _url.host]];
-
- NSArray *proxies = CFBridgingRelease(CFNetworkCopyProxiesForAutoConfigurationScript((__bridge CFStringRef)script,(__bridge CFURLRef)httpURL, &err));
- if (!err && [proxies count] > 0) {
- NSDictionary *settings = [proxies objectAtIndex:0];
- NSString *proxyType = settings[(NSString *)kCFProxyTypeKey];
- [self _readProxySettingWithType:proxyType settings:settings];
- }
- [self _openConnection];
-}
-
-- (void)_openConnection
-{
- [self _initializeStreams];
-
- [self.inputStream scheduleInRunLoop:[NSRunLoop SR_networkRunLoop]
- forMode:NSDefaultRunLoopMode];
- //[self.outputStream scheduleInRunLoop:[NSRunLoop SR_networkRunLoop]
- // forMode:NSDefaultRunLoopMode];
- [self.outputStream open];
- [self.inputStream open];
-}
-
-- (void)_initializeStreams
-{
- assert(_url.port.unsignedIntValue <= UINT32_MAX);
- uint32_t port = _url.port.unsignedIntValue;
- if (port == 0) {
- port = (_connectionRequiresSSL ? 443 : 80);
- }
- NSString *host = _url.host;
-
- if (_httpProxyHost) {
- host = _httpProxyHost;
- port = (_httpProxyPort ?: 80);
- }
-
- CFReadStreamRef readStream = NULL;
- CFWriteStreamRef writeStream = NULL;
-
- SRDebugLog(@"ProxyConnect connect stream to %@:%u", host, port);
- CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
-
- self.outputStream = CFBridgingRelease(writeStream);
- self.inputStream = CFBridgingRelease(readStream);
-
- if (_socksProxyHost) {
- SRDebugLog(@"ProxyConnect set sock property stream to %@:%u user %@ password %@", _socksProxyHost, _socksProxyPort, _socksProxyUsername, _socksProxyPassword);
- NSMutableDictionary *settings = [NSMutableDictionary dictionaryWithCapacity:4];
- settings[NSStreamSOCKSProxyHostKey] = _socksProxyHost;
- if (_socksProxyPort) {
- settings[NSStreamSOCKSProxyPortKey] = @(_socksProxyPort);
- }
- if (_socksProxyUsername) {
- settings[NSStreamSOCKSProxyUserKey] = _socksProxyUsername;
- }
- if (_socksProxyPassword) {
- settings[NSStreamSOCKSProxyPasswordKey] = _socksProxyPassword;
- }
- [self.inputStream setProperty:settings forKey:NSStreamSOCKSProxyConfigurationKey];
- [self.outputStream setProperty:settings forKey:NSStreamSOCKSProxyConfigurationKey];
- }
- self.inputStream.delegate = self;
- self.outputStream.delegate = self;
-}
-
-- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
-{
- SRDebugLog(@"stream handleEvent %u", eventCode);
- switch (eventCode) {
- case NSStreamEventOpenCompleted: {
- if (aStream == self.inputStream) {
- if (_httpProxyHost) {
- [self _proxyDidConnect];
- } else {
- [self _didConnect];
- }
- }
- } break;
- case NSStreamEventErrorOccurred: {
- [self _failWithError:aStream.streamError];
- } break;
- case NSStreamEventEndEncountered: {
- [self _failWithError:aStream.streamError];
- } break;
- case NSStreamEventHasBytesAvailable: {
- if (aStream == _inputStream) {
- [self _processInputStream];
- }
- } break;
- case NSStreamEventHasSpaceAvailable:
- case NSStreamEventNone:
- SRDebugLog(@"(default) %@", aStream);
- break;
- }
-}
-
-- (void)_proxyDidConnect
-{
- SRDebugLog(@"Proxy Connected");
- uint32_t port = _url.port.unsignedIntValue;
- if (port == 0) {
- port = (_connectionRequiresSSL ? 443 : 80);
- }
- // Send HTTP CONNECT Request
- NSString *connectRequestStr = [NSString stringWithFormat:@"CONNECT %@:%u HTTP/1.1\r\nHost: %@\r\nConnection: keep-alive\r\nProxy-Connection: keep-alive\r\n\r\n", _url.host, port, _url.host];
-
- NSData *message = [connectRequestStr dataUsingEncoding:NSUTF8StringEncoding];
- SRDebugLog(@"Proxy sending %@", connectRequestStr);
-
- [self _writeData:message];
-}
-
-///handles the incoming bytes and sending them to the proper processing method
-- (void)_processInputStream
-{
- NSMutableData *buf = [NSMutableData dataWithCapacity:SRDefaultBufferSize()];
- uint8_t *buffer = buf.mutableBytes;
- NSInteger length = [_inputStream read:buffer maxLength:SRDefaultBufferSize()];
-
- if (length <= 0) {
- return;
- }
-
- BOOL process = (_inputQueue.count == 0);
- [_inputQueue addObject:[NSData dataWithBytes:buffer length:length]];
-
- if (process) {
- [self _dequeueInput];
- }
-}
-
-// dequeue the incoming input so it is processed in order
-
-- (void)_dequeueInput
-{
- while (_inputQueue.count > 0) {
- NSData *data = _inputQueue.firstObject;
- [_inputQueue removeObjectAtIndex:0];
-
- // No need to process any data further, we got the full header data.
- if ([self _proxyProcessHTTPResponseWithData:data]) {
- break;
- }
- }
-}
-//handle checking the proxy connection status
-- (BOOL)_proxyProcessHTTPResponseWithData:(NSData *)data
-{
- if (_receivedHTTPHeaders == NULL) {
- _receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO);
- }
-
- CFHTTPMessageAppendBytes(_receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length);
- if (CFHTTPMessageIsHeaderComplete(_receivedHTTPHeaders)) {
- SRDebugLog(@"Finished reading headers %@", CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_receivedHTTPHeaders)));
- [self _proxyHTTPHeadersDidFinish];
- return YES;
- }
-
- return NO;
-}
-
-- (void)_proxyHTTPHeadersDidFinish
-{
- NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(_receivedHTTPHeaders);
-
- if (responseCode >= 299) {
- SRDebugLog(@"Connect to Proxy Request failed with response code %d", responseCode);
- NSError *error = SRHTTPErrorWithCodeDescription(responseCode, 2132,
- [NSString stringWithFormat:@"Received bad response code from proxy server: %d.",
- (int)responseCode]);
- [self _failWithError:error];
- return;
- }
- SRDebugLog(@"proxy connect return %d, call socket connect", responseCode);
- [self _didConnect];
-}
-
-static NSTimeInterval const SRProxyConnectWriteTimeout = 5.0;
-
-- (void)_writeData:(NSData *)data
-{
- const uint8_t * bytes = data.bytes;
- __block NSInteger timeout = (NSInteger)(SRProxyConnectWriteTimeout * 1000000); // wait timeout before giving up
- __weak typeof(self) wself = self;
- dispatch_async(_writeQueue, ^{
- __strong typeof(wself) sself = self;
- if (!sself) {
- return;
- }
- NSOutputStream *outStream = sself.outputStream;
- if (!outStream) {
- return;
- }
- while (![outStream hasSpaceAvailable]) {
- usleep(100); //wait until the socket is ready
- timeout -= 100;
- if (timeout < 0) {
- NSError *error = SRHTTPErrorWithCodeDescription(408, 2132, @"Proxy timeout");
- [sself _failWithError:error];
- } else if (outStream.streamError != nil) {
- [sself _failWithError:outStream.streamError];
- }
- }
- [outStream write:bytes maxLength:data.length];
- });
-}
-
-@end
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface SRRunLoopThread : NSThread
-
-@property (nonatomic, strong, readonly) NSRunLoop *runLoop;
-
-+ (instancetype)sharedThread;
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRRunLoopThread.h"
-
-@interface SRRunLoopThread ()
-{
- dispatch_group_t _waitGroup;
-}
-
-@property (nonatomic, strong, readwrite) NSRunLoop *runLoop;
-
-@end
-
-@implementation SRRunLoopThread
-
-+ (instancetype)sharedThread
-{
- static SRRunLoopThread *thread;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- thread = [[SRRunLoopThread alloc] init];
- thread.name = @"com.facebook.SocketRocket.NetworkThread";
- thread.qualityOfService = NSQualityOfServiceUserInitiated;
- [thread start];
- });
- return thread;
-}
-
-- (instancetype)init
-{
- self = [super init];
- if (self) {
- _waitGroup = dispatch_group_create();
- dispatch_group_enter(_waitGroup);
- }
- return self;
-}
-
-- (void)main
-{
- @autoreleasepool {
- _runLoop = [NSRunLoop currentRunLoop];
- dispatch_group_leave(_waitGroup);
-
- // Add an empty run loop source to prevent runloop from spinning.
- CFRunLoopSourceContext sourceCtx = {
- .version = 0,
- .info = NULL,
- .retain = NULL,
- .release = NULL,
- .copyDescription = NULL,
- .equal = NULL,
- .hash = NULL,
- .schedule = NULL,
- .cancel = NULL,
- .perform = NULL
- };
- CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &sourceCtx);
- CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
- CFRelease(source);
-
- while ([_runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
-
- }
- assert(NO);
- }
-}
-
-- (NSRunLoop *)runLoop
-{
- dispatch_group_wait(_waitGroup, DISPATCH_TIME_FOREVER);
- return _runLoop;
-}
-
-@end
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-typedef NS_ENUM(uint8_t, SROpCode)
-{
- SROpCodeTextFrame = 0x1,
- SROpCodeBinaryFrame = 0x2,
- // 3-7 reserved.
- SROpCodeConnectionClose = 0x8,
- SROpCodePing = 0x9,
- SROpCodePong = 0xA,
- // B-F reserved.
-};
-
-/**
- Default buffer size that is used for reading/writing to streams.
- */
-extern size_t SRDefaultBufferSize(void);
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRConstants.h"
-
-size_t SRDefaultBufferSize(void) {
- static size_t size;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- size = getpagesize();
- });
- return size;
-}
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-#import <SocketRocket/SRSecurityPolicy.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-/**
- * NOTE: While publicly, SocketRocket does not support configuring the security policy with pinned certificates,
- * it is still possible to manually construct a security policy of this class. If you do this, note that you may
- * be open to MitM attacks, and we will not support any issues you may have. Dive at your own risk.
- */
-@interface SRPinningSecurityPolicy : SRSecurityPolicy
-
-- (instancetype)initWithCertificates:(NSArray *)pinnedCertificates;
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRPinningSecurityPolicy.h"
-
-#import <Foundation/Foundation.h>
-
-#import "SRLog.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface SRPinningSecurityPolicy ()
-
-@property (nonatomic, copy, readonly) NSArray *pinnedCertificates;
-
-@end
-
-@implementation SRPinningSecurityPolicy
-
-- (instancetype)initWithCertificates:(NSArray *)pinnedCertificates
-{
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated"
- // Do not validate certificate chain since we're pinning to specific certificates.
- self = [super initWithCertificateChainValidationEnabled:NO];
-#pragma clang diagnostic pop
-
- if (!self) { return self; }
-
- if (pinnedCertificates.count == 0) {
- @throw [NSException exceptionWithName:@"Creating security policy failed."
- reason:@"Must specify at least one certificate when creating a pinning policy."
- userInfo:nil];
- }
- _pinnedCertificates = [pinnedCertificates copy];
-
- return self;
-}
-
-- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain
-{
- SRDebugLog(@"Pinned cert count: %d", self.pinnedCertificates.count);
- NSUInteger requiredCertCount = self.pinnedCertificates.count;
-
- NSUInteger validatedCertCount = 0;
- CFIndex serverCertCount = SecTrustGetCertificateCount(serverTrust);
- for (CFIndex i = 0; i < serverCertCount; i++) {
- SecCertificateRef cert = SecTrustGetCertificateAtIndex(serverTrust, i);
- NSData *data = CFBridgingRelease(SecCertificateCopyData(cert));
- for (id ref in self.pinnedCertificates) {
- SecCertificateRef trustedCert = (__bridge SecCertificateRef)ref;
- // TODO: (nlutsenko) Add caching, so we don't copy the data for every pinned cert all the time.
- NSData *trustedCertData = CFBridgingRelease(SecCertificateCopyData(trustedCert));
- if ([trustedCertData isEqualToData:data]) {
- validatedCertCount++;
- break;
- }
- }
- }
- return (requiredCertCount == validatedCertCount);
-}
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-extern NSError *SRErrorWithDomainCodeDescription(NSString *domain, NSInteger code, NSString *description);
-extern NSError *SRErrorWithCodeDescription(NSInteger code, NSString *description);
-extern NSError *SRErrorWithCodeDescriptionUnderlyingError(NSInteger code, NSString *description, NSError *underlyingError);
-
-extern NSError *SRHTTPErrorWithCodeDescription(NSInteger httpCode, NSInteger errorCode, NSString *description);
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRError.h"
-
-#import "SRWebSocket.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-NSError *SRErrorWithDomainCodeDescription(NSString *domain, NSInteger code, NSString *description)
-{
- return [NSError errorWithDomain:domain code:code userInfo:@{ NSLocalizedDescriptionKey: description }];
-}
-
-NSError *SRErrorWithCodeDescription(NSInteger code, NSString *description)
-{
- return SRErrorWithDomainCodeDescription(SRWebSocketErrorDomain, code, description);
-}
-
-NSError *SRErrorWithCodeDescriptionUnderlyingError(NSInteger code, NSString *description, NSError *underlyingError)
-{
- return [NSError errorWithDomain:SRWebSocketErrorDomain
- code:code
- userInfo:@{ NSLocalizedDescriptionKey: description,
- NSUnderlyingErrorKey: underlyingError }];
-}
-
-NSError *SRHTTPErrorWithCodeDescription(NSInteger httpCode, NSInteger errorCode, NSString *description)
-{
- return [NSError errorWithDomain:SRWebSocketErrorDomain
- code:errorCode
- userInfo:@{ NSLocalizedDescriptionKey: description,
- SRHTTPResponseErrorKey: @(httpCode) }];
-}
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-#import <CFNetwork/CFNetwork.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-extern CFHTTPMessageRef SRHTTPConnectMessageCreate(NSURLRequest *request,
- NSString *securityKey,
- uint8_t webSocketProtocolVersion,
- NSArray<NSHTTPCookie *> *_Nullable cookies,
- NSArray<NSString *> *_Nullable requestedProtocols);
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRHTTPConnectMessage.h"
-
-#import "SRURLUtilities.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-static NSString *_SRHTTPConnectMessageHost(NSURL *url)
-{
- NSString *host = url.host;
- if (url.port) {
- host = [host stringByAppendingFormat:@":%@", url.port];
- }
- return host;
-}
-
-CFHTTPMessageRef SRHTTPConnectMessageCreate(NSURLRequest *request,
- NSString *securityKey,
- uint8_t webSocketProtocolVersion,
- NSArray<NSHTTPCookie *> *_Nullable cookies,
- NSArray<NSString *> *_Nullable requestedProtocols)
-{
- NSURL *url = request.URL;
-
- CFHTTPMessageRef message = CFHTTPMessageCreateRequest(NULL, (__bridge CFStringRef)request.HTTPMethod, (__bridge CFURLRef)url, kCFHTTPVersion1_1);
-
- // Set host first so it defaults
- CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Host"), (__bridge CFStringRef)_SRHTTPConnectMessageHost(url));
-
- // Apply cookies if any have been provided
- if (cookies) {
- NSDictionary<NSString *, NSString *> *messageCookies = [NSHTTPCookie requestHeaderFieldsWithCookies:(NSArray<NSHTTPCookie*> *_Nonnull)cookies];
- [messageCookies enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
- if (key.length && obj.length) {
- CFHTTPMessageSetHeaderFieldValue(message, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
- }
- }];
- }
-
- // set header for http basic auth
- NSString *basicAuthorizationString = SRBasicAuthorizationHeaderFromURL(url);
- if (basicAuthorizationString) {
- CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Authorization"), (__bridge CFStringRef)basicAuthorizationString);
- }
-
- CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Upgrade"), CFSTR("websocket"));
- CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Connection"), CFSTR("Upgrade"));
- CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Sec-WebSocket-Key"), (__bridge CFStringRef)securityKey);
- CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Sec-WebSocket-Version"), (__bridge CFStringRef)@(webSocketProtocolVersion).stringValue);
-
- CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Origin"), (__bridge CFStringRef)SRURLOrigin(url));
-
- if (requestedProtocols.count) {
- CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Sec-WebSocket-Protocol"),
- (__bridge CFStringRef)[requestedProtocols componentsJoinedByString:@", "]);
- }
-
- [request.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
- CFHTTPMessageSetHeaderFieldValue(message, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
- }];
-
- return message;
-}
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-extern NSData *SRSHA1HashFromString(NSString *string);
-extern NSData *SRSHA1HashFromBytes(const char *bytes, size_t length);
-
-extern NSString *SRBase64EncodedStringFromData(NSData *data);
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRHash.h"
-
-#import <CommonCrypto/CommonDigest.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-NSData *SRSHA1HashFromString(NSString *string)
-{
- const char *utf8String = string.UTF8String;
- if (!utf8String) {
- return [NSData data];
- }
- size_t length = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
- return SRSHA1HashFromBytes(utf8String, length);
-}
-
-NSData *SRSHA1HashFromBytes(const char *bytes, size_t length)
-{
- uint8_t outputLength = CC_SHA1_DIGEST_LENGTH;
- unsigned char output[outputLength];
- CC_SHA1(bytes, (CC_LONG)length, output);
-
- return [NSData dataWithBytes:output length:outputLength];
-}
-
-NSString *SRBase64EncodedStringFromData(NSData *data)
-{
- if ([data respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
- return [data base64EncodedStringWithOptions:0];
- }
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- return [data base64Encoding];
-#pragma clang diagnostic pop
-}
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-// Uncomment this line to enable debug logging
-//#define SR_DEBUG_LOG_ENABLED
-
-extern void SRErrorLog(NSString *format, ...);
-extern void SRDebugLog(NSString *format, ...);
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRLog.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-extern void SRErrorLog(NSString *format, ...)
-{
- __block va_list arg_list;
- va_start (arg_list, format);
-
- NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list];
-
- va_end(arg_list);
-
- NSLog(@"[SocketRocket] %@", formattedString);
-}
-
-extern void SRDebugLog(NSString *format, ...)
-{
-#ifdef SR_DEBUG_LOG_ENABLED
- SRErrorLog(tag, format);
-#endif
-}
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-typedef __attribute__((capability("mutex"))) pthread_mutex_t *SRMutex;
-
-extern SRMutex SRMutexInitRecursive(void);
-extern void SRMutexDestroy(SRMutex mutex);
-
-extern void SRMutexLock(SRMutex mutex) __attribute__((acquire_capability(mutex)));
-extern void SRMutexUnlock(SRMutex mutex) __attribute__((release_capability(mutex)));
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRMutex.h"
-
-#import <pthread/pthread.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-SRMutex SRMutexInitRecursive(void)
-{
- pthread_mutex_t *mutex = malloc(sizeof(pthread_mutex_t));
- pthread_mutexattr_t attributes;
-
- pthread_mutexattr_init(&attributes);
- pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(mutex, &attributes);
- pthread_mutexattr_destroy(&attributes);
-
- return mutex;
-}
-
-void SRMutexDestroy(SRMutex mutex)
-{
- pthread_mutex_destroy(mutex);
- free(mutex);
-}
-
-__attribute__((no_thread_safety_analysis))
-void SRMutexLock(SRMutex mutex)
-{
- pthread_mutex_lock(mutex);
-}
-
-__attribute__((no_thread_safety_analysis))
-void SRMutexUnlock(SRMutex mutex)
-{
- pthread_mutex_unlock(mutex);
-}
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-extern NSData *SRRandomData(NSUInteger length);
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRRandom.h"
-
-#import <Security/SecRandom.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-NSData *SRRandomData(NSUInteger length)
-{
- NSMutableData *_Nullable data = [NSMutableData dataWithLength:length];
- if (data == nil) {
- [NSException raise:NSInternalInconsistencyException format:@"Failed to allocate random data"];
- }
- int result = SecRandomCopyBytes(kSecRandomDefault, data.length, ((NSMutableData *_Nonnull)data).mutableBytes);
- if (result != errSecSuccess) {
- [NSException raise:NSInternalInconsistencyException format:@"Failed to generate random bytes with OSStatus: %d", result];
- }
- return (NSMutableData *_Nonnull)data;
-}
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-/**
- Unmask bytes using XOR via SIMD.
-
- @param bytes The bytes to unmask.
- @param length The number of bytes to unmask.
- @param maskKey The mask to XOR with MUST be of length sizeof(uint32_t).
- */
-void SRMaskBytesSIMD(uint8_t *bytes, size_t length, uint8_t *maskKey);
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRSIMDHelpers.h"
-
-typedef uint8_t uint8x32_t __attribute__((vector_size(32)));
-
-static void SRMaskBytesManual(uint8_t *bytes, size_t length, uint8_t *maskKey) {
- for (size_t i = 0; i < length; i++) {
- bytes[i] = bytes[i] ^ maskKey[i % sizeof(uint32_t)];
- }
-}
-
-/**
- Right-shift the elements of a vector, circularly.
-
- @param vector The vector to circular shift.
- @param by The number of elements to shift by.
-
- @return A shifted vector.
- */
-static uint8x32_t SRShiftVector(uint8x32_t vector, size_t by) {
- uint8x32_t vectorCopy = vector;
- by = by % _Alignof(uint8x32_t);
-
- uint8_t *vectorPointer = (uint8_t *)&vector;
- uint8_t *vectorCopyPointer = (uint8_t *)&vectorCopy;
-
- memmove(vectorPointer + by, vectorPointer, sizeof(vector) - by);
- memcpy(vectorPointer, vectorCopyPointer + (sizeof(vector) - by), by);
-
- return vector;
-}
-
-void SRMaskBytesSIMD(uint8_t *bytes, size_t length, uint8_t *maskKey) {
- size_t alignmentBytes = _Alignof(uint8x32_t) - ((uintptr_t)bytes % _Alignof(uint8x32_t));
- if (alignmentBytes == _Alignof(uint8x32_t)) {
- alignmentBytes = 0;
- }
-
- // If the number of bytes that can be processed after aligning is
- // less than the number of bytes we can put into a vector,
- // then there's no work to do with SIMD, just call the manual version.
- if (alignmentBytes > length || (length - alignmentBytes) < sizeof(uint8x32_t)) {
- SRMaskBytesManual(bytes, length, maskKey);
- return;
- }
-
- size_t vectorLength = (length - alignmentBytes) / sizeof(uint8x32_t);
- size_t manualStartOffset = alignmentBytes + (vectorLength * sizeof(uint8x32_t));
- size_t manualLength = length - manualStartOffset;
-
- uint8x32_t *vector = (uint8x32_t *)(bytes + alignmentBytes);
- uint8x32_t maskVector;
-
- memset_pattern4(&maskVector, maskKey, sizeof(uint8x32_t));
- maskVector = SRShiftVector(maskVector, alignmentBytes);
-
- SRMaskBytesManual(bytes, alignmentBytes, maskKey);
-
- for (size_t vectorIndex = 0; vectorIndex < vectorLength; vectorIndex++) {
- vector[vectorIndex] = vector[vectorIndex] ^ maskVector;
- }
-
- // Use the shifted mask for the final manual part.
- SRMaskBytesManual(bytes + manualStartOffset, manualLength, (uint8_t *) &maskVector);
-}
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-// The origin isn't really applicable for a native application.
-// So instead, just map ws -> http and wss -> https.
-extern NSString *SRURLOrigin(NSURL *url);
-
-extern BOOL SRURLRequiresSSL(NSURL *_Nullable url);
-
-// Extracts `user` and `password` from url (if available) into `Basic base64(user:password)`.
-extern NSString *_Nullable SRBasicAuthorizationHeaderFromURL(NSURL *url);
-
-// Returns a valid value for `NSStreamNetworkServiceType` or `nil`.
-extern NSString *_Nullable SRStreamNetworkServiceTypeFromURLRequest(NSURLRequest *request);
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRURLUtilities.h"
-
-#import "SRHash.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-NSString *SRURLOrigin(NSURL *url)
-{
- NSMutableString *origin = [NSMutableString string];
-
- NSString *scheme = url.scheme.lowercaseString;
- if ([scheme isEqualToString:@"wss"]) {
- scheme = @"https";
- } else if ([scheme isEqualToString:@"ws"]) {
- scheme = @"http";
- }
- [origin appendFormat:@"%@://%@", scheme, url.host];
-
- NSNumber *port = url.port;
- BOOL portIsDefault = (!port ||
- ([scheme isEqualToString:@"http"] && port.integerValue == 80) ||
- ([scheme isEqualToString:@"https"] && port.integerValue == 443));
- if (!portIsDefault) {
- [origin appendFormat:@":%@", port.stringValue];
- }
- return origin;
-}
-
-extern BOOL SRURLRequiresSSL(NSURL *_Nullable url)
-{
- NSString *scheme = url.scheme.lowercaseString;
- return ([scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"]);
-}
-
-extern NSString *_Nullable SRBasicAuthorizationHeaderFromURL(NSURL *url)
-{
- if (!url.user || !url.password) {
- return nil;
- }
-
- NSData *data = [[NSString stringWithFormat:@"%@:%@", url.user, url.password] dataUsingEncoding:NSUTF8StringEncoding];
- return [NSString stringWithFormat:@"Basic %@", SRBase64EncodedStringFromData(data)];
-}
-
-extern NSString *_Nullable SRStreamNetworkServiceTypeFromURLRequest(NSURLRequest *request)
-{
- NSString *networkServiceType = nil;
- switch (request.networkServiceType) {
- case NSURLNetworkServiceTypeDefault:
- case NSURLNetworkServiceTypeResponsiveData:
- case NSURLNetworkServiceTypeAVStreaming:
- case NSURLNetworkServiceTypeResponsiveAV:
- break;
- case NSURLNetworkServiceTypeVoIP:
- networkServiceType = NSStreamNetworkServiceTypeVoIP;
- break;
- case NSURLNetworkServiceTypeVideo:
- networkServiceType = NSStreamNetworkServiceTypeVideo;
- break;
- case NSURLNetworkServiceTypeBackground:
- networkServiceType = NSStreamNetworkServiceTypeBackground;
- break;
- case NSURLNetworkServiceTypeVoice:
- networkServiceType = NSStreamNetworkServiceTypeVoice;
- break;
-#if (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 || __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 || __TV_OS_VERSION_MAX_ALLOWED >= 100000 || __WATCH_OS_VERSION_MAX_ALLOWED >= 30000)
- case NSURLNetworkServiceTypeCallSignaling: {
- if (@available(iOS 10.0, tvOS 10.0, macOS 10.12, *)) {
- networkServiceType = NSStreamNetworkServiceTypeCallSignaling;
- }
- } break;
-#endif
- }
- return networkServiceType;
-}
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface NSRunLoop (SRWebSocket)
-
-/**
- Default run loop that will be used to schedule all instances of `SRWebSocket`.
-
- @return An instance of `NSRunLoop`.
- */
-+ (NSRunLoop *)SR_networkRunLoop;
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "NSRunLoop+SRWebSocket.h"
-#import "NSRunLoop+SRWebSocketPrivate.h"
-
-#import "SRRunLoopThread.h"
-
-// Required for object file to always be linked.
-void import_NSRunLoop_SRWebSocket(void) { }
-
-@implementation NSRunLoop (SRWebSocket)
-
-+ (NSRunLoop *)SR_networkRunLoop
-{
- return [SRRunLoopThread sharedThread].runLoop;
-}
-
-@end
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface NSURLRequest (SRWebSocket)
-
-/**
- An array of pinned `SecCertificateRef` SSL certificates that `SRWebSocket` will use for validation.
- */
-@property (nullable, nonatomic, copy, readonly) NSArray *SR_SSLPinnedCertificates
- DEPRECATED_MSG_ATTRIBUTE("Using pinned certificates is neither secure nor supported in SocketRocket, "
- "and leads to security issues. Please use a proper, trust chain validated certificate.");
-
-@end
-
-@interface NSMutableURLRequest (SRWebSocket)
-
-/**
- An array of pinned `SecCertificateRef` SSL certificates that `SRWebSocket` will use for validation.
- */
-@property (nullable, nonatomic, copy) NSArray *SR_SSLPinnedCertificates
- DEPRECATED_MSG_ATTRIBUTE("Using pinned certificates is neither secure nor supported in SocketRocket, "
- "and leads to security issues. Please use a proper, trust chain validated certificate.");
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "NSURLRequest+SRWebSocket.h"
-#import "NSURLRequest+SRWebSocketPrivate.h"
-
-// Required for object file to always be linked.
-void import_NSURLRequest_SRWebSocket(void) { }
-
-NS_ASSUME_NONNULL_BEGIN
-
-static NSString *const SRSSLPinnnedCertificatesKey = @"SocketRocket_SSLPinnedCertificates";
-
-@implementation NSURLRequest (SRWebSocket)
-
-- (nullable NSArray *)SR_SSLPinnedCertificates
-{
- return nil;
-}
-
-@end
-
-@implementation NSMutableURLRequest (SRWebSocket)
-
-- (void)setSR_SSLPinnedCertificates:(nullable NSArray *)SR_SSLPinnedCertificates
-{
- [NSException raise:NSInvalidArgumentException
- format:@"Using pinned certificates is neither secure nor supported in SocketRocket, "
- "and leads to security issues. Please use a proper, trust chain validated certificate."];
-}
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-#import <Security/Security.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface SRSecurityPolicy : NSObject
-
-/**
- A default `SRSecurityPolicy` implementation specifies socket security and
- validates the certificate chain.
-
- Use a subclass of `SRSecurityPolicy` for more fine grained customization.
- */
-+ (instancetype)defaultPolicy;
-
-/**
- Specifies socket security and provider certificate pinning, disregarding certificate
- chain validation.
-
- @param pinnedCertificates Array of `SecCertificateRef` SSL certificates to use for validation.
- */
-+ (instancetype)pinnningPolicyWithCertificates:(NSArray *)pinnedCertificates
- DEPRECATED_MSG_ATTRIBUTE("Using pinned certificates is neither secure nor supported in SocketRocket, "
- "and leads to security issues. Please use a proper, trust chain validated certificate.");
-
-/**
- Specifies socket security and optional certificate chain validation.
-
- @param enabled Whether or not to validate the SSL certificate chain. If you
- are considering using this method because your certificate was not issued by a
- recognized certificate authority, consider using `pinningPolicyWithCertificates` instead.
- */
-- (instancetype)initWithCertificateChainValidationEnabled:(BOOL)enabled
- DEPRECATED_MSG_ATTRIBUTE("Disabling certificate chain validation is unsafe. "
- "Please use a proper Certificate Authority to issue your TLS certificates.")
- NS_DESIGNATED_INITIALIZER;
-
-/**
- Updates all the security options for input and output streams, for example you
- can set your socket security level here.
-
- @param stream Stream to update the options in.
- */
-- (void)updateSecurityOptionsInStream:(NSStream *)stream;
-
-/**
- Whether or not the specified server trust should be accepted, based on the security policy.
-
- This method should be used when responding to an authentication challenge from
- a server. In the default implemenation, no further validation is done here, but
- you're free to override it in a subclass. See `SRPinningSecurityPolicy.h` for
- an example.
-
- @param serverTrust The X.509 certificate trust of the server.
- @param domain The domain of serverTrust.
-
- @return Whether or not to trust the server.
- */
-- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain;
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright (c) 2016-present, Facebook, Inc.
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRSecurityPolicy.h"
-#import "SRPinningSecurityPolicy.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface SRSecurityPolicy ()
-
-@property (nonatomic, assign, readonly) BOOL certificateChainValidationEnabled;
-
-@end
-
-@implementation SRSecurityPolicy
-
-+ (instancetype)defaultPolicy
-{
- return [self new];
-}
-
-+ (instancetype)pinnningPolicyWithCertificates:(NSArray *)pinnedCertificates
-{
- [NSException raise:NSInvalidArgumentException
- format:@"Using pinned certificates is neither secure nor supported in SocketRocket, "
- "and leads to security issues. Please use a proper, trust chain validated certificate."];
-
- return nil;
-}
-
-- (instancetype)initWithCertificateChainValidationEnabled:(BOOL)enabled
-{
- self = [super init];
- if (!self) { return self; }
-
- _certificateChainValidationEnabled = enabled;
-
- return self;
-}
-
-- (instancetype)init
-{
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated"
-
- return [self initWithCertificateChainValidationEnabled:YES];
-
-#pragma clang diagnostic pop
-}
-
-- (void)updateSecurityOptionsInStream:(NSStream *)stream
-{
- // Enforce TLS 1.2
- [stream setProperty:(__bridge id)CFSTR("kCFStreamSocketSecurityLevelTLSv1_2") forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel];
-
- // Validate certificate chain for this stream if enabled.
- NSDictionary<NSString *, id> *sslOptions = @{ (__bridge NSString *)kCFStreamSSLValidatesCertificateChain : @(self.certificateChainValidationEnabled) };
- [stream setProperty:sslOptions forKey:(__bridge NSString *)kCFStreamPropertySSLSettings];
-}
-
-- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain
-{
- // No further evaluation happens in the default policy.
- return YES;
-}
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-typedef NS_ENUM(NSInteger, SRReadyState) {
- SR_CONNECTING = 0,
- SR_OPEN = 1,
- SR_CLOSING = 2,
- SR_CLOSED = 3,
-};
-
-typedef NS_ENUM(NSInteger, SRStatusCode) {
- // 0-999: Reserved and not used.
- SRStatusCodeNormal = 1000,
- SRStatusCodeGoingAway = 1001,
- SRStatusCodeProtocolError = 1002,
- SRStatusCodeUnhandledType = 1003,
- // 1004 reserved.
- SRStatusNoStatusReceived = 1005,
- SRStatusCodeAbnormal = 1006,
- SRStatusCodeInvalidUTF8 = 1007,
- SRStatusCodePolicyViolated = 1008,
- SRStatusCodeMessageTooBig = 1009,
- SRStatusCodeMissingExtension = 1010,
- SRStatusCodeInternalError = 1011,
- SRStatusCodeServiceRestart = 1012,
- SRStatusCodeTryAgainLater = 1013,
- // 1014: Reserved for future use by the WebSocket standard.
- SRStatusCodeTLSHandshake = 1015,
- // 1016-1999: Reserved for future use by the WebSocket standard.
- // 2000-2999: Reserved for use by WebSocket extensions.
- // 3000-3999: Available for use by libraries and frameworks. May not be used by applications. Available for registration at the IANA via first-come, first-serve.
- // 4000-4999: Available for use by applications.
-};
-
-@class SRWebSocket;
-@class SRSecurityPolicy;
-
-/**
- Error domain used for errors reported by SRWebSocket.
- */
-extern NSString *const SRWebSocketErrorDomain;
-
-/**
- Key used for HTTP status code if bad response was received from the server.
- */
-extern NSString *const SRHTTPResponseErrorKey;
-
-@protocol SRWebSocketDelegate;
-
-///--------------------------------------
-#pragma mark - SRWebSocket
-///--------------------------------------
-
-/**
- A `SRWebSocket` object lets you connect, send and receive data to a remote Web Socket.
- */
-@interface SRWebSocket : NSObject <NSStreamDelegate>
-
-/**
- The delegate of the web socket.
-
- The web socket delegate is notified on all state changes that happen to the web socket.
- */
-@property (nonatomic, weak) id <SRWebSocketDelegate> delegate;
-
-/**
- A dispatch queue for scheduling the delegate calls. The queue doesn't need be a serial queue.
-
- If `nil` and `delegateOperationQueue` is `nil`, the socket uses main queue for performing all delegate method calls.
- */
-@property (nullable, nonatomic, strong) dispatch_queue_t delegateDispatchQueue;
-
-/**
- An operation queue for scheduling the delegate calls.
-
- If `nil` and `delegateOperationQueue` is `nil`, the socket uses main queue for performing all delegate method calls.
- */
-@property (nullable, nonatomic, strong) NSOperationQueue *delegateOperationQueue;
-
-/**
- Current ready state of the socket. Default: `SR_CONNECTING`.
-
- This property is Key-Value Observable and fully thread-safe.
- */
-@property (atomic, assign, readonly) SRReadyState readyState;
-
-/**
- An instance of `NSURL` that this socket connects to.
- */
-@property (nullable, nonatomic, strong, readonly) NSURL *url;
-
-/**
- All HTTP headers that were received by socket or `nil` if none were received so far.
- */
-@property (nullable, nonatomic, assign, readonly) CFHTTPMessageRef receivedHTTPHeaders;
-
-/**
- Array of `NSHTTPCookie` cookies to apply to the connection.
- */
-@property (nullable, nonatomic, copy) NSArray<NSHTTPCookie *> *requestCookies;
-
-/**
- The negotiated web socket protocol or `nil` if handshake did not yet complete.
- */
-@property (nullable, nonatomic, copy, readonly) NSString *protocol;
-
-/**
- A boolean value indicating whether this socket will allow connection without SSL trust chain evaluation.
- For DEBUG builds this flag is ignored, and SSL connections are allowed regardless of the certificate trust configuration
- */
-@property (nonatomic, assign, readonly) BOOL allowsUntrustedSSLCertificates;
-
-///--------------------------------------
-#pragma mark - Constructors
-///--------------------------------------
-
-/**
- Initializes a web socket with a given `NSURLRequest`.
-
- @param request Request to initialize with.
- */
-- (instancetype)initWithURLRequest:(NSURLRequest *)request;
-
-/**
- Initializes a web socket with a given `NSURLRequest`, specifying a transport security policy (e.g. SSL configuration).
-
- @param request Request to initialize with.
- @param securityPolicy Policy object describing transport security behavior.
- */
-- (instancetype)initWithURLRequest:(NSURLRequest *)request securityPolicy:(SRSecurityPolicy *)securityPolicy;
-
-/**
- Initializes a web socket with a given `NSURLRequest` and list of sub-protocols.
-
- @param request Request to initialize with.
- @param protocols An array of strings that turn into `Sec-WebSocket-Protocol`. Default: `nil`.
- */
-- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(nullable NSArray<NSString *> *)protocols;
-
-/**
- Initializes a web socket with a given `NSURLRequest`, list of sub-protocols and whether untrusted SSL certificates are allowed.
-
- @param request Request to initialize with.
- @param protocols An array of strings that turn into `Sec-WebSocket-Protocol`. Default: `nil`.
- @param allowsUntrustedSSLCertificates Boolean value indicating whether untrusted SSL certificates are allowed. Default: `false`.
- */
-- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(nullable NSArray<NSString *> *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates
- DEPRECATED_MSG_ATTRIBUTE("Disabling certificate chain validation is unsafe. "
- "Please use a proper Certificate Authority to issue your TLS certificates.");
-
-/**
- Initializes a web socket with a given `NSURLRequest`, list of sub-protocols and whether untrusted SSL certificates are allowed.
-
- @param request Request to initialize with.
- @param protocols An array of strings that turn into `Sec-WebSocket-Protocol`. Default: `nil`.
- @param securityPolicy Policy object describing transport security behavior.
- */
-- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(nullable NSArray<NSString *> *)protocols securityPolicy:(SRSecurityPolicy *)securityPolicy NS_DESIGNATED_INITIALIZER;
-
-/**
- Initializes a web socket with a given `NSURL`.
-
- @param url URL to initialize with.
- */
-- (instancetype)initWithURL:(NSURL *)url;
-
-/**
- Initializes a web socket with a given `NSURL` and list of sub-protocols.
-
- @param url URL to initialize with.
- @param protocols An array of strings that turn into `Sec-WebSocket-Protocol`. Default: `nil`.
- */
-- (instancetype)initWithURL:(NSURL *)url protocols:(nullable NSArray<NSString *> *)protocols;
-
-/**
- Initializes a web socket with a given `NSURL`, specifying a transport security policy (e.g. SSL configuration).
-
- @param url URL to initialize with.
- @param securityPolicy Policy object describing transport security behavior.
- */
-- (instancetype)initWithURL:(NSURL *)url securityPolicy:(SRSecurityPolicy *)securityPolicy;
-
-/**
- Initializes a web socket with a given `NSURL`, list of sub-protocols and whether untrusted SSL certificates are allowed.
-
- @param url URL to initialize with.
- @param protocols An array of strings that turn into `Sec-WebSocket-Protocol`. Default: `nil`.
- @param allowsUntrustedSSLCertificates Boolean value indicating whether untrusted SSL certificates are allowed. Default: `false`.
- */
-- (instancetype)initWithURL:(NSURL *)url protocols:(nullable NSArray<NSString *> *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates
- DEPRECATED_MSG_ATTRIBUTE("Disabling certificate chain validation is unsafe. "
- "Please use a proper Certificate Authority to issue your TLS certificates.");
-
-/**
- Unavailable initializer. Please use any other initializer.
- */
-- (instancetype)init NS_UNAVAILABLE;
-
-/**
- Unavailable constructor. Please use any other initializer.
- */
-+ (instancetype)new NS_UNAVAILABLE;
-
-///--------------------------------------
-#pragma mark - Schedule
-///--------------------------------------
-
-/**
- Schedules a received on a given run loop in a given mode.
- By default, a web socket will schedule itself on `+[NSRunLoop SR_networkRunLoop]` using `NSDefaultRunLoopMode`.
-
- @param runLoop The run loop on which to schedule the receiver.
- @param mode The mode for the run loop.
- */
-- (void)scheduleInRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode NS_SWIFT_NAME(schedule(in:forMode:));
-
-/**
- Removes the receiver from a given run loop running in a given mode.
-
- @param runLoop The run loop on which the receiver was scheduled.
- @param mode The mode for the run loop.
- */
-- (void)unscheduleFromRunLoop:(NSRunLoop *)runLoop forMode:(NSString *)mode NS_SWIFT_NAME(unschedule(from:forMode:));
-
-///--------------------------------------
-#pragma mark - Open / Close
-///--------------------------------------
-
-/**
- Opens web socket, which will trigger connection, authentication and start receiving/sending events.
- An instance of `SRWebSocket` is intended for one-time-use only. This method should be called once and only once.
- */
-- (void)open;
-
-/**
- Closes a web socket using `SRStatusCodeNormal` code and no reason.
- */
-- (void)close;
-
-/**
- Closes a web socket using a given code and reason.
-
- @param code Code to close the socket with.
- @param reason Reason to send to the server or `nil`.
- */
-- (void)closeWithCode:(NSInteger)code reason:(nullable NSString *)reason;
-
-///--------------------------------------
-#pragma mark Send
-///--------------------------------------
-
-/**
- Send a UTF-8 string or binary data to the server.
-
- @param message UTF-8 String or Data to send.
-
- @deprecated Please use `sendString:` or `sendData` instead.
- */
-- (void)send:(nullable id)message __attribute__((deprecated("Please use `sendString:error:` or `sendData:error:` instead.")));
-
-/**
- Send a UTF-8 String to the server.
-
- @param string String to send.
- @param error On input, a pointer to variable for an `NSError` object.
- If an error occurs, this pointer is set to an `NSError` object containing information about the error.
- You may specify `nil` to ignore the error information.
-
- @return `YES` if the string was scheduled to send, otherwise - `NO`.
- */
-- (BOOL)sendString:(NSString *)string error:(NSError **)error NS_SWIFT_NAME(send(string:));
-
-/**
- Send binary data to the server.
-
- @param data Data to send.
- @param error On input, a pointer to variable for an `NSError` object.
- If an error occurs, this pointer is set to an `NSError` object containing information about the error.
- You may specify `nil` to ignore the error information.
-
- @return `YES` if the string was scheduled to send, otherwise - `NO`.
- */
-- (BOOL)sendData:(nullable NSData *)data error:(NSError **)error NS_SWIFT_NAME(send(data:));
-
-/**
- Send binary data to the server, without making a defensive copy of it first.
-
- @param data Data to send.
- @param error On input, a pointer to variable for an `NSError` object.
- If an error occurs, this pointer is set to an `NSError` object containing information about the error.
- You may specify `nil` to ignore the error information.
-
- @return `YES` if the string was scheduled to send, otherwise - `NO`.
- */
-- (BOOL)sendDataNoCopy:(nullable NSData *)data error:(NSError **)error NS_SWIFT_NAME(send(dataNoCopy:));
-
-/**
- Send Ping message to the server with optional data.
-
- @param data Instance of `NSData` or `nil`.
- @param error On input, a pointer to variable for an `NSError` object.
- If an error occurs, this pointer is set to an `NSError` object containing information about the error.
- You may specify `nil` to ignore the error information.
-
- @return `YES` if the string was scheduled to send, otherwise - `NO`.
- */
-- (BOOL)sendPing:(nullable NSData *)data error:(NSError **)error NS_SWIFT_NAME(sendPing(_:));
-
-@end
-
-///--------------------------------------
-#pragma mark - SRWebSocketDelegate
-///--------------------------------------
-
-/**
- The `SRWebSocketDelegate` protocol describes the methods that `SRWebSocket` objects
- call on their delegates to handle status and messsage events.
- */
-@protocol SRWebSocketDelegate <NSObject>
-
-@optional
-
-#pragma mark Receive Messages
-
-/**
- Called when any message was received from a web socket.
- This method is suboptimal and might be deprecated in a future release.
-
- @param webSocket An instance of `SRWebSocket` that received a message.
- @param message Received message. Either a `String` or `NSData`.
- */
-- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
-
-/**
- Called when a frame was received from a web socket.
-
- @param webSocket An instance of `SRWebSocket` that received a message.
- @param string Received text in a form of UTF-8 `String`.
- */
-- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithString:(NSString *)string;
-
-/**
- Called when a frame was received from a web socket.
-
- @param webSocket An instance of `SRWebSocket` that received a message.
- @param data Received data in a form of `NSData`.
- */
-- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessageWithData:(NSData *)data;
-
-#pragma mark Status & Connection
-
-/**
- Called when a given web socket was open and authenticated.
-
- @param webSocket An instance of `SRWebSocket` that was open.
- */
-- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
-
-/**
- Called when a given web socket encountered an error.
-
- @param webSocket An instance of `SRWebSocket` that failed with an error.
- @param error An instance of `NSError`.
- */
-- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
-
-/**
- Called when a given web socket was closed.
-
- @param webSocket An instance of `SRWebSocket` that was closed.
- @param code Code reported by the server.
- @param reason Reason in a form of a String that was reported by the server or `nil`.
- @param wasClean Boolean value indicating whether a socket was closed in a clean state.
- */
-- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(nullable NSString *)reason wasClean:(BOOL)wasClean;
-
-/**
- Called on receive of a ping message from the server.
-
- @param webSocket An instance of `SRWebSocket` that received a ping frame.
- @param data Payload that was received or `nil` if there was no payload.
- */
-- (void)webSocket:(SRWebSocket *)webSocket didReceivePingWithData:(nullable NSData *)data;
-
-/**
- Called when a pong data was received in response to ping.
-
- @param webSocket An instance of `SRWebSocket` that received a pong frame.
- @param pongData Payload that was received or `nil` if there was no payload.
- */
-- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(nullable NSData *)pongData;
-
-/**
- Sent before reporting a text frame to be able to configure if it shuold be convert to a UTF-8 String or passed as `NSData`.
- If the method is not implemented - it will always convert text frames to String.
-
- @param webSocket An instance of `SRWebSocket` that received a text frame.
-
- @return `YES` if text frame should be converted to UTF-8 String, otherwise - `NO`. Default: `YES`.
- */
-- (BOOL)webSocketShouldConvertTextFrameToString:(SRWebSocket *)webSocket NS_SWIFT_NAME(webSocketShouldConvertTextFrameToString(_:));
-
-@end
-
-NS_ASSUME_NONNULL_END
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import "SRWebSocket.h"
-
-#if __has_include(<unicode/utf8.h>)
-#define HAS_ICU
-#endif
-
-#ifdef HAS_ICU
-#import <unicode/utf8.h>
-#endif
-
-#import <os/lock.h>
-
-#import "SRDelegateController.h"
-#import "SRIOConsumer.h"
-#import "SRIOConsumerPool.h"
-#import "SRHash.h"
-#import "SRURLUtilities.h"
-#import "SRError.h"
-#import "NSURLRequest+SRWebSocket.h"
-#import "NSRunLoop+SRWebSocket.h"
-#import "SRProxyConnect.h"
-#import "SRSecurityPolicy.h"
-#import "SRHTTPConnectMessage.h"
-#import "SRRandom.h"
-#import "SRLog.h"
-#import "SRMutex.h"
-#import "SRSIMDHelpers.h"
-#import "NSURLRequest+SRWebSocketPrivate.h"
-#import "NSRunLoop+SRWebSocketPrivate.h"
-#import "SRConstants.h"
-
-#if !__has_feature(objc_arc)
-#error SocketRocket must be compiled with ARC enabled
-#endif
-
-__attribute__((used)) static void importCategories(void)
-{
- import_NSURLRequest_SRWebSocket();
- import_NSRunLoop_SRWebSocket();
-}
-
-typedef struct {
- BOOL fin;
- // BOOL rsv1;
- // BOOL rsv2;
- // BOOL rsv3;
- uint8_t opcode;
- BOOL masked;
- uint64_t payload_length;
-} frame_header;
-
-static NSString *const SRWebSocketAppendToSecKeyString = @"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
-
-static inline int32_t validate_dispatch_data_partial_string(NSData *data);
-
-static uint8_t const SRWebSocketProtocolVersion = 13;
-
-NSString *const SRWebSocketErrorDomain = @"SRWebSocketErrorDomain";
-NSString *const SRHTTPResponseErrorKey = @"HTTPResponseStatusCode";
-
-@interface SRWebSocket () <NSStreamDelegate>
-
-@property (atomic, assign, readwrite) SRReadyState readyState;
-
-// Specifies whether SSL trust chain should NOT be evaluated.
-// By default this flag is set to NO, meaning only secure SSL connections are allowed.
-// For DEBUG builds this flag is ignored, and SSL connections are allowed regardless
-// of the certificate trust configuration
-@property (nonatomic, assign, readwrite) BOOL allowsUntrustedSSLCertificates;
-
-@property (nonatomic, strong, readonly) SRDelegateController *delegateController;
-
-@end
-
-@implementation SRWebSocket {
- SRMutex _kvoLock;
- os_unfair_lock _propertyLock;
-
- dispatch_queue_t _workQueue;
- NSMutableArray<SRIOConsumer *> *_consumers;
-
- NSInputStream *_inputStream;
- NSOutputStream *_outputStream;
-
- dispatch_data_t _readBuffer;
- NSUInteger _readBufferOffset;
-
- dispatch_data_t _outputBuffer;
- NSUInteger _outputBufferOffset;
-
- uint8_t _currentFrameOpcode;
- size_t _currentFrameCount;
- size_t _readOpCount;
- uint32_t _currentStringScanPosition;
- NSMutableData *_currentFrameData;
-
- NSString *_closeReason;
-
- NSString *_secKey;
-
- SRSecurityPolicy *_securityPolicy;
- BOOL _requestRequiresSSL;
- BOOL _streamSecurityValidated;
-
- uint8_t _currentReadMaskKey[4];
- size_t _currentReadMaskOffset;
-
- BOOL _closeWhenFinishedWriting;
- BOOL _failed;
-
- NSURLRequest *_urlRequest;
-
- BOOL _sentClose;
- BOOL _didFail;
- BOOL _cleanupScheduled;
- int _closeCode;
-
- BOOL _isPumping;
-
- NSMutableSet<NSArray *> *_scheduledRunloops; // Set<[RunLoop, Mode]>. TODO: (nlutsenko) Fix clowntown
-
- // We use this to retain ourselves.
- __strong SRWebSocket *_selfRetain;
-
- NSArray<NSString *> *_requestedProtocols;
- SRIOConsumerPool *_consumerPool;
-
- // proxy support
- SRProxyConnect *_proxyConnect;
-}
-
-@synthesize readyState = _readyState;
-
-///--------------------------------------
-#pragma mark - Init
-///--------------------------------------
-
-- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols securityPolicy:(SRSecurityPolicy *)securityPolicy
-{
- self = [super init];
- if (!self) return self;
-
- assert(request.URL);
- _url = request.URL;
- _urlRequest = request;
- _requestedProtocols = [protocols copy];
- _securityPolicy = securityPolicy;
- _requestRequiresSSL = SRURLRequiresSSL(_url);
-
- _readyState = SR_CONNECTING;
-
- _propertyLock = OS_UNFAIR_LOCK_INIT;
- _kvoLock = SRMutexInitRecursive();
- _workQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
-
- // Going to set a specific on the queue so we can validate we're on the work queue
- dispatch_queue_set_specific(_workQueue, (__bridge void *)self, (__bridge void *)(_workQueue), NULL);
-
- _delegateController = [[SRDelegateController alloc] init];
-
- _readBuffer = dispatch_data_empty;
- _outputBuffer = dispatch_data_empty;
-
- _currentFrameData = [[NSMutableData alloc] init];
-
- _consumers = [[NSMutableArray alloc] init];
-
- _consumerPool = [[SRIOConsumerPool alloc] init];
-
- _scheduledRunloops = [[NSMutableSet alloc] init];
-
- return self;
-}
-
-- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates
-{
- SRSecurityPolicy *securityPolicy;
- NSArray *pinnedCertificates = request.SR_SSLPinnedCertificates;
- if (pinnedCertificates) {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated"
- securityPolicy = [SRSecurityPolicy pinnningPolicyWithCertificates:pinnedCertificates];
-#pragma clang diagnostic pop
- } else {
- BOOL certificateChainValidationEnabled = !allowsUntrustedSSLCertificates;
- securityPolicy = [[SRSecurityPolicy alloc] initWithCertificateChainValidationEnabled:certificateChainValidationEnabled];
- }
-
- return [self initWithURLRequest:request protocols:protocols securityPolicy:securityPolicy];
-}
-
-- (instancetype)initWithURLRequest:(NSURLRequest *)request securityPolicy:(SRSecurityPolicy *)securityPolicy
-{
- return [self initWithURLRequest:request protocols:nil securityPolicy:securityPolicy];
-}
-
-- (instancetype)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray<NSString *> *)protocols
-{
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated"
- return [self initWithURLRequest:request protocols:protocols allowsUntrustedSSLCertificates:NO];
-#pragma clang diagnostic pop
-}
-
-- (instancetype)initWithURLRequest:(NSURLRequest *)request
-{
- return [self initWithURLRequest:request protocols:nil];
-}
-
-- (instancetype)initWithURL:(NSURL *)url
-{
- return [self initWithURL:url protocols:nil];
-}
-
-- (instancetype)initWithURL:(NSURL *)url protocols:(NSArray<NSString *> *)protocols
-{
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated"
- return [self initWithURL:url protocols:protocols allowsUntrustedSSLCertificates:NO];
-#pragma clang diagnostic pop
-}
-
-- (instancetype)initWithURL:(NSURL *)url securityPolicy:(SRSecurityPolicy *)securityPolicy
-{
- NSURLRequest *request = [NSURLRequest requestWithURL:url];
- return [self initWithURLRequest:request protocols:nil securityPolicy:securityPolicy];
-}
-
-- (instancetype)initWithURL:(NSURL *)url protocols:(NSArray<NSString *> *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates
-{
- NSURLRequest *request = [NSURLRequest requestWithURL:url];
- return [self initWithURLRequest:request protocols:protocols allowsUntrustedSSLCertificates:allowsUntrustedSSLCertificates];
-}
-
-- (void)assertOnWorkQueue
-{
- assert(dispatch_get_specific((__bridge void *)self) == (__bridge void *)_workQueue);
-}
-
-///--------------------------------------
-#pragma mark - Dealloc
-///--------------------------------------
-
-- (void)dealloc
-{
- _inputStream.delegate = nil;
- _outputStream.delegate = nil;
-
- [_inputStream close];
- [_outputStream close];
-
- if (_receivedHTTPHeaders) {
- CFRelease(_receivedHTTPHeaders);
- _receivedHTTPHeaders = NULL;
- }
-
- SRMutexDestroy(_kvoLock);
-}
-
-///--------------------------------------
-#pragma mark - Accessors
-///--------------------------------------
-
-#pragma mark readyState
-
-- (void)setReadyState:(SRReadyState)readyState
-{
- @try {
- SRMutexLock(_kvoLock);
- if (_readyState != readyState) {
- [self willChangeValueForKey:@"readyState"];
- os_unfair_lock_lock(&_propertyLock);
- _readyState = readyState;
- os_unfair_lock_unlock(&_propertyLock);
- [self didChangeValueForKey:@"readyState"];
- }
- }
- @finally {
- SRMutexUnlock(_kvoLock);
- }
-}
-
-- (SRReadyState)readyState
-{
- SRReadyState state = 0;
- os_unfair_lock_lock(&_propertyLock);
- state = _readyState;
- os_unfair_lock_unlock(&_propertyLock);
- return state;
-}
-
-+ (BOOL)automaticallyNotifiesObserversOfReadyState {
- return NO;
-}
-
-///--------------------------------------
-#pragma mark - Open / Close
-///--------------------------------------
-
-- (void)open
-{
- NSURL* const url = _url;
- if (!url) {
- NSError *error = SRErrorWithDomainCodeDescription(NSURLErrorDomain, NSURLErrorBadURL, @"Unable to open socket with emtpy URL.");
- [self _failWithError:error];
- return;
- }
- NSAssert(self.readyState == SR_CONNECTING, @"Cannot call -(void)open on SRWebSocket more than once.");
-
- _selfRetain = self;
-
- if (_urlRequest.timeoutInterval > 0) {
- dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_urlRequest.timeoutInterval * NSEC_PER_SEC));
- __weak typeof(self) wself = self;
- dispatch_after(popTime, dispatch_get_main_queue(), ^{
- __strong SRWebSocket *sself = wself;
- if (!sself) {
- return;
- }
- if (sself.readyState == SR_CONNECTING) {
- NSError *error = SRErrorWithDomainCodeDescription(NSURLErrorDomain, NSURLErrorTimedOut, @"Timed out connecting to server.");
- [sself _failWithError:error];
- }
- });
- }
-
- _proxyConnect = [[SRProxyConnect alloc] initWithURL:url];
-
- __weak typeof(self) wself = self;
- [_proxyConnect openNetworkStreamWithCompletion:^(NSError *error, NSInputStream *readStream, NSOutputStream *writeStream) {
- [wself _connectionDoneWithError:error readStream:readStream writeStream:writeStream];
- }];
-}
-
-- (void)_connectionDoneWithError:(NSError *)error readStream:(NSInputStream *)readStream writeStream:(NSOutputStream *)writeStream
-{
- if (error != nil) {
- [self _failWithError:error];
- } else {
- _outputStream = writeStream;
- _inputStream = readStream;
-
- _inputStream.delegate = self;
- _outputStream.delegate = self;
- [self _updateSecureStreamOptions];
-
- if (!_scheduledRunloops.count) {
- [self scheduleInRunLoop:[NSRunLoop SR_networkRunLoop] forMode:NSDefaultRunLoopMode];
- }
-
- // If we don't require SSL validation - consider that we connected.
- // Otherwise `didConnect` is called when SSL validation finishes.
- if (!_requestRequiresSSL) {
- dispatch_async(_workQueue, ^{
- [self didConnect];
- });
- }
- }
- // Schedule to run on a work queue, to make sure we don't run this inline and deallocate `self` inside `SRProxyConnect`.
- // TODO: (nlutsenko) Find a better structure for this, maybe Bolts Tasks?
- dispatch_async(_workQueue, ^{
- self->_proxyConnect = nil;
- });
-}
-
-- (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage
-{
- NSString *acceptHeader = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(httpMessage, CFSTR("Sec-WebSocket-Accept")));
-
- if (acceptHeader == nil) {
- return NO;
- }
-
- NSString *concattedString = [_secKey stringByAppendingString:SRWebSocketAppendToSecKeyString];
- NSData *hashedString = SRSHA1HashFromString(concattedString);
- NSString *expectedAccept = SRBase64EncodedStringFromData(hashedString);
- return [acceptHeader isEqualToString:expectedAccept];
-}
-
-- (void)_HTTPHeadersDidFinish:(CFHTTPMessageRef)httpMessage
-{
- NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(httpMessage);
- if (responseCode >= 400) {
- SRDebugLog(@"Request failed with response code %d", responseCode);
- NSError *error = SRHTTPErrorWithCodeDescription(responseCode, 2132,
- [NSString stringWithFormat:@"Received bad response code from server: %d.",
- (int)responseCode]);
- [self _failWithError:error];
- return;
- }
-
- if(![self _checkHandshake:httpMessage]) {
- NSError *error = SRErrorWithCodeDescription(2133, @"Invalid Sec-WebSocket-Accept response.");
- [self _failWithError:error];
- return;
- }
-
- NSString *negotiatedProtocol = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(httpMessage, CFSTR("Sec-WebSocket-Protocol")));
- if (negotiatedProtocol) {
- // Make sure we requested the protocol
- if ([_requestedProtocols indexOfObject:negotiatedProtocol] == NSNotFound) {
- NSError *error = SRErrorWithCodeDescription(2133, @"Server specified Sec-WebSocket-Protocol that wasn't requested.");
- [self _failWithError:error];
- return;
- }
-
- _protocol = negotiatedProtocol;
- }
-
- self.readyState = SR_OPEN;
-
- if (!_didFail) {
- [self _readFrameNew];
- }
-
- [self.delegateController performDelegateBlock:^(id<SRWebSocketDelegate> _Nullable delegate, SRDelegateAvailableMethods availableMethods) {
- if (availableMethods.didOpen) {
- [delegate webSocketDidOpen:self];
- }
- }];
-}
-
-
-- (void)_readHTTPHeader
-{
- if (_receivedHTTPHeaders == NULL) {
- _receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO);
- }
-
- [self _readUntilHeaderCompleteWithCallback:^(SRWebSocket *socket, NSData *data) {
- if (!socket) {
- return;
- }
- CFHTTPMessageRef receivedHTTPHeaders = socket->_receivedHTTPHeaders;
-
- CFHTTPMessageAppendBytes(receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length);
-
- if (CFHTTPMessageIsHeaderComplete(receivedHTTPHeaders)) {
- SRDebugLog(@"Finished reading headers %@", CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(receivedHTTPHeaders)));
- [socket _HTTPHeadersDidFinish:receivedHTTPHeaders];
- } else {
- [socket _readHTTPHeader];
- }
- }];
-}
-
-- (void)didConnect
-{
- SRDebugLog(@"Connected");
-
- _secKey = SRBase64EncodedStringFromData(SRRandomData(16));
- assert([_secKey length] == 24);
-
- CFHTTPMessageRef message = SRHTTPConnectMessageCreate(_urlRequest,
- _secKey,
- SRWebSocketProtocolVersion,
- self.requestCookies,
- _requestedProtocols);
-
- NSData *messageData = CFBridgingRelease(CFHTTPMessageCopySerializedMessage(message));
-
- CFRelease(message);
-
- [self _writeData:messageData];
- [self _readHTTPHeader];
-}
-
-- (void)_updateSecureStreamOptions
-{
- if (_requestRequiresSSL) {
- SRDebugLog(@"Setting up security for streams.");
- [_securityPolicy updateSecurityOptionsInStream:_inputStream];
- [_securityPolicy updateSecurityOptionsInStream:_outputStream];
- }
-
- NSString *networkServiceType = SRStreamNetworkServiceTypeFromURLRequest(_urlRequest);
- if (networkServiceType != nil) {
- [_inputStream setProperty:networkServiceType forKey:NSStreamNetworkServiceType];
- [_outputStream setProperty:networkServiceType forKey:NSStreamNetworkServiceType];
- }
-}
-
-- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
-{
- [_outputStream scheduleInRunLoop:aRunLoop forMode:mode];
- [_inputStream scheduleInRunLoop:aRunLoop forMode:mode];
-
- [_scheduledRunloops addObject:@[aRunLoop, mode]];
-}
-
-- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
-{
- [_outputStream removeFromRunLoop:aRunLoop forMode:mode];
- [_inputStream removeFromRunLoop:aRunLoop forMode:mode];
-
- [_scheduledRunloops removeObject:@[aRunLoop, mode]];
-}
-
-- (void)close
-{
- [self closeWithCode:SRStatusCodeNormal reason:nil];
-}
-
-- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason
-{
- assert(code);
- __weak typeof(self) wself = self;
- dispatch_async(_workQueue, ^{
- __strong SRWebSocket *sself = wself;
- if (!sself) {
- return;
- }
- if (sself.readyState == SR_CLOSING || sself.readyState == SR_CLOSED) {
- return;
- }
-
- BOOL wasConnecting = sself.readyState == SR_CONNECTING;
-
- sself.readyState = SR_CLOSING;
-
- SRDebugLog(@"Closing with code %d reason %@", code, reason);
-
- if (wasConnecting) {
- [sself closeConnection];
- return;
- }
-
- size_t maxMsgSize = [reason maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
- NSMutableData *mutablePayload = [[NSMutableData alloc] initWithLength:sizeof(uint16_t) + maxMsgSize];
- NSData *payload = mutablePayload;
-
- ((uint16_t *)mutablePayload.mutableBytes)[0] = CFSwapInt16BigToHost((uint16_t)code);
-
- if (reason) {
- NSRange remainingRange = {0};
-
- NSUInteger usedLength = 0;
-
- BOOL success = [reason getBytes:(char *)mutablePayload.mutableBytes + sizeof(uint16_t) maxLength:payload.length - sizeof(uint16_t) usedLength:&usedLength encoding:NSUTF8StringEncoding options:NSStringEncodingConversionExternalRepresentation range:NSMakeRange(0, reason.length) remainingRange:&remainingRange];
-#pragma unused (success)
-
- assert(success);
- assert(remainingRange.length == 0);
-
- if (usedLength != maxMsgSize) {
- payload = [payload subdataWithRange:NSMakeRange(0, usedLength + sizeof(uint16_t))];
- }
- }
-
-
- [sself _sendFrameWithOpcode:SROpCodeConnectionClose data:payload];
- });
-}
-
-- (void)_closeWithProtocolError:(NSString *)message
-{
- // Need to shunt this on the _callbackQueue first to see if they received any messages
- [self.delegateController performDelegateQueueBlock:^{
- [self closeWithCode:SRStatusCodeProtocolError reason:message];
- dispatch_async(self->_workQueue, ^{
- [self closeConnection];
- });
- }];
-}
-
-- (void)_failWithError:(NSError *)error
-{
- dispatch_async(_workQueue, ^{
- if (self.readyState != SR_CLOSED) {
- self->_failed = YES;
- [self.delegateController performDelegateBlock:^(id<SRWebSocketDelegate> _Nullable delegate, SRDelegateAvailableMethods availableMethods) {
- if (availableMethods.didFailWithError) {
- [delegate webSocket:self didFailWithError:error];
- }
- }];
-
- self.readyState = SR_CLOSED;
-
- SRDebugLog(@"Failing with error %@", error.localizedDescription);
-
- [self closeConnection];
- [self _scheduleCleanup];
- }
- });
-}
-
-- (void)_writeData:(NSData *)data
-{
- [self assertOnWorkQueue];
-
- if (_closeWhenFinishedWriting) {
- return;
- }
-
- __block NSData *strongData = data;
- dispatch_data_t newData = dispatch_data_create(data.bytes, data.length, nil, ^{
- strongData = nil;
- });
- (void)strongData;
- _outputBuffer = dispatch_data_create_concat(_outputBuffer, newData);
- [self _pumpWriting];
-}
-
-- (void)send:(nullable id)message
-{
- if (!message) {
- [self sendData:nil error:nil]; // Send Data, but it doesn't matter since we are going to send the same text frame with 0 length.
- } else if ([message isKindOfClass:[NSString class]]) {
- [self sendString:(NSString *_Nonnull)message error:nil];
- } else if ([message isKindOfClass:[NSData class]]) {
- [self sendData:message error:nil];
- } else {
- NSAssert(NO, @"Unrecognized message. Not able to send anything other than a String or NSData.");
- }
-}
-
-- (BOOL)sendString:(NSString *)string error:(NSError **)error
-{
- if (self.readyState != SR_OPEN) {
- NSString *message = @"Invalid State: Cannot call `sendString:error:` until connection is open.";
- if (error) {
- *error = SRErrorWithCodeDescription(2134, message);
- }
- SRDebugLog(message);
- return NO;
- }
-
- string = [string copy];
- dispatch_async(_workQueue, ^{
- [self _sendFrameWithOpcode:SROpCodeTextFrame data:[string dataUsingEncoding:NSUTF8StringEncoding]];
- });
- return YES;
-}
-
-- (BOOL)sendData:(nullable NSData *)data error:(NSError **)error
-{
- data = [data copy];
- return [self sendDataNoCopy:data error:error];
-}
-
-- (BOOL)sendDataNoCopy:(nullable NSData *)data error:(NSError **)error
-{
- if (self.readyState != SR_OPEN) {
- NSString *message = @"Invalid State: Cannot call `sendDataNoCopy:error:` until connection is open.";
- if (error) {
- *error = SRErrorWithCodeDescription(2134, message);
- }
- SRDebugLog(message);
- return NO;
- }
-
- dispatch_async(_workQueue, ^{
- if (data) {
- [self _sendFrameWithOpcode:SROpCodeBinaryFrame data:data];
- } else {
- [self _sendFrameWithOpcode:SROpCodeTextFrame data:nil];
- }
- });
- return YES;
-}
-
-- (BOOL)sendPing:(nullable NSData *)data error:(NSError **)error
-{
- if (self.readyState != SR_OPEN) {
- NSString *message = @"Invalid State: Cannot call `sendPing:error:` until connection is open.";
- if (error) {
- *error = SRErrorWithCodeDescription(2134, message);
- }
- SRDebugLog(message);
- return NO;
- }
-
- data = [data copy] ?: [NSData data]; // It's okay for a ping to be empty
- dispatch_async(_workQueue, ^{
- [self _sendFrameWithOpcode:SROpCodePing data:data];
- });
- return YES;
-}
-
-- (void)_handlePingWithData:(nullable NSData *)data
-{
- // Need to pingpong this off _callbackQueue first to make sure messages happen in order
- [self.delegateController performDelegateBlock:^(id<SRWebSocketDelegate> _Nullable delegate, SRDelegateAvailableMethods availableMethods) {
- if (availableMethods.didReceivePing) {
- [delegate webSocket:self didReceivePingWithData:data];
- }
- dispatch_async(self->_workQueue, ^{
- [self _sendFrameWithOpcode:SROpCodePong data:data];
- });
- }];
-}
-
-- (void)handlePong:(NSData *)pongData
-{
- SRDebugLog(@"Received pong");
- [self.delegateController performDelegateBlock:^(id<SRWebSocketDelegate> _Nullable delegate, SRDelegateAvailableMethods availableMethods) {
- if (availableMethods.didReceivePong) {
- [delegate webSocket:self didReceivePong:pongData];
- }
- }];
-}
-
-
-static inline BOOL closeCodeIsValid(int closeCode) {
- if (closeCode < 1000) {
- return NO;
- }
-
- if (closeCode >= 1000 && closeCode <= 1011) {
- if (closeCode == 1004 ||
- closeCode == 1005 ||
- closeCode == 1006) {
- return NO;
- }
- return YES;
- }
-
- if (closeCode >= 3000 && closeCode <= 3999) {
- return YES;
- }
-
- if (closeCode >= 4000 && closeCode <= 4999) {
- return YES;
- }
-
- return NO;
-}
-
-// Note from RFC:
-//
-// If there is a body, the first two
-// bytes of the body MUST be a 2-byte unsigned integer (in network byte
-// order) representing a status code with value /code/ defined in
-// Section 7.4. Following the 2-byte integer the body MAY contain UTF-8
-// encoded data with value /reason/, the interpretation of which is not
-// defined by this specification.
-
-- (void)handleCloseWithData:(NSData *)data
-{
- size_t dataSize = data.length;
- __block uint16_t closeCode = 0;
-
- SRDebugLog(@"Received close frame");
-
- if (dataSize == 1) {
- // TODO handle error
- [self _closeWithProtocolError:@"Payload for close must be larger than 2 bytes"];
- return;
- } else if (dataSize >= 2) {
- [data getBytes:&closeCode length:sizeof(closeCode)];
- _closeCode = CFSwapInt16BigToHost(closeCode);
- if (!closeCodeIsValid(_closeCode)) {
- [self _closeWithProtocolError:[NSString stringWithFormat:@"Cannot have close code of %d", _closeCode]];
- return;
- }
- if (dataSize > 2) {
- _closeReason = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(2, dataSize - 2)] encoding:NSUTF8StringEncoding];
- if (!_closeReason) {
- [self _closeWithProtocolError:@"Close reason MUST be valid UTF-8"];
- return;
- }
- }
- } else {
- _closeCode = SRStatusNoStatusReceived;
- }
-
- [self assertOnWorkQueue];
-
- if (self.readyState == SR_OPEN) {
- [self closeWithCode:1000 reason:nil];
- }
- dispatch_async(_workQueue, ^{
- [self closeConnection];
- });
-}
-
-- (void)closeConnection
-{
- [self assertOnWorkQueue];
- SRDebugLog(@"Trying to disconnect");
- _closeWhenFinishedWriting = YES;
- [self _pumpWriting];
-}
-
-- (void)_handleFrameWithData:(NSData *)frameData opCode:(SROpCode)opcode
-{
- // Check that the current data is valid UTF8
-
- BOOL isControlFrame = (opcode == SROpCodePing || opcode == SROpCodePong || opcode == SROpCodeConnectionClose);
- if (isControlFrame) {
- //frameData will be copied before passing to handlers
- //otherwise there can be misbehaviours when value at the pointer is changed
- frameData = [frameData copy];
-
- dispatch_async(_workQueue, ^{
- [self _readFrameContinue];
- });
- } else {
- [self _readFrameNew];
- }
-
- switch (opcode) {
- case SROpCodeTextFrame: {
- NSString *string = [[NSString alloc] initWithData:frameData encoding:NSUTF8StringEncoding];
- if (!string && frameData) {
- [self closeWithCode:SRStatusCodeInvalidUTF8 reason:@"Text frames must be valid UTF-8."];
- dispatch_async(_workQueue, ^{
- [self closeConnection];
- });
- return;
- }
- SRDebugLog(@"Received text message.");
- [self.delegateController performDelegateBlock:^(id<SRWebSocketDelegate> _Nullable delegate, SRDelegateAvailableMethods availableMethods) {
- // Don't convert into string - iff `delegate` tells us not to. Otherwise - create UTF8 string and handle that.
- if (availableMethods.shouldConvertTextFrameToString && ![delegate webSocketShouldConvertTextFrameToString:self]) {
- if (availableMethods.didReceiveMessage) {
- [delegate webSocket:self didReceiveMessage:frameData];
- }
- if (availableMethods.didReceiveMessageWithData) {
- [delegate webSocket:self didReceiveMessageWithData:frameData];
- }
- } else {
- if (availableMethods.didReceiveMessage) {
- [delegate webSocket:self didReceiveMessage:string];
- }
- if (availableMethods.didReceiveMessageWithString) {
- [delegate webSocket:self didReceiveMessageWithString:string];
- }
- }
- }];
- break;
- }
- case SROpCodeBinaryFrame: {
- SRDebugLog(@"Received data message.");
- [self.delegateController performDelegateBlock:^(id<SRWebSocketDelegate> _Nullable delegate, SRDelegateAvailableMethods availableMethods) {
- if (availableMethods.didReceiveMessage) {
- [delegate webSocket:self didReceiveMessage:frameData];
- }
- if (availableMethods.didReceiveMessageWithData) {
- [delegate webSocket:self didReceiveMessageWithData:frameData];
- }
- }];
- }
- break;
- case SROpCodeConnectionClose:
- [self handleCloseWithData:frameData];
- break;
- case SROpCodePing:
- [self _handlePingWithData:frameData];
- break;
- case SROpCodePong:
- [self handlePong:frameData];
- break;
- default:
- [self _closeWithProtocolError:[NSString stringWithFormat:@"Unknown opcode %ld", (long)opcode]];
- // TODO: Handle invalid opcode
- break;
- }
-}
-
-- (void)_handleFrameHeader:(frame_header)frame_header curData:(NSData *)curData
-{
- assert(frame_header.opcode != 0);
-
- if (self.readyState == SR_CLOSED) {
- return;
- }
-
-
- BOOL isControlFrame = (frame_header.opcode == SROpCodePing || frame_header.opcode == SROpCodePong || frame_header.opcode == SROpCodeConnectionClose);
-
- if (isControlFrame && !frame_header.fin) {
- [self _closeWithProtocolError:@"Fragmented control frames not allowed"];
- return;
- }
-
- if (isControlFrame && frame_header.payload_length >= 126) {
- [self _closeWithProtocolError:@"Control frames cannot have payloads larger than 126 bytes"];
- return;
- }
-
- if (!isControlFrame) {
- _currentFrameOpcode = frame_header.opcode;
- _currentFrameCount += 1;
- }
-
- if (frame_header.payload_length == 0) {
- if (isControlFrame) {
- [self _handleFrameWithData:curData opCode:frame_header.opcode];
- } else {
- if (frame_header.fin) {
- [self _handleFrameWithData:_currentFrameData opCode:frame_header.opcode];
- } else {
- // TODO add assert that opcode is not a control;
- [self _readFrameContinue];
- }
- }
- } else {
- assert(frame_header.payload_length <= SIZE_T_MAX);
- [self _addConsumerWithDataLength:(size_t)frame_header.payload_length callback:^(SRWebSocket *sself, NSData *newData) {
- if (isControlFrame) {
- [sself _handleFrameWithData:newData opCode:frame_header.opcode];
- } else {
- if (frame_header.fin) {
- [sself _handleFrameWithData:sself->_currentFrameData opCode:frame_header.opcode];
- } else {
- // TODO add assert that opcode is not a control;
- [sself _readFrameContinue];
- }
- }
- } readToCurrentFrame:!isControlFrame unmaskBytes:frame_header.masked];
- }
-}
-
-/* From RFC:
-
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-------+-+-------------+-------------------------------+
- |F|R|R|R| opcode|M| Payload len | Extended payload length |
- |I|S|S|S| (4) |A| (7) | (16/64) |
- |N|V|V|V| |S| | (if payload len==126/127) |
- | |1|2|3| |K| | |
- +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
- | Extended payload length continued, if payload len == 127 |
- + - - - - - - - - - - - - - - - +-------------------------------+
- | |Masking-key, if MASK set to 1 |
- +-------------------------------+-------------------------------+
- | Masking-key (continued) | Payload Data |
- +-------------------------------- - - - - - - - - - - - - - - - +
- : Payload Data continued ... :
- + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
- | Payload Data continued ... |
- +---------------------------------------------------------------+
- */
-
-static const uint8_t SRFinMask = 0x80;
-static const uint8_t SROpCodeMask = 0x0F;
-static const uint8_t SRRsvMask = 0x70;
-static const uint8_t SRMaskMask = 0x80;
-static const uint8_t SRPayloadLenMask = 0x7F;
-
-
-- (void)_readFrameContinue
-{
- assert((_currentFrameCount == 0 && _currentFrameOpcode == 0) || (_currentFrameCount > 0 && _currentFrameOpcode > 0));
-
- [self _addConsumerWithDataLength:2 callback:^(SRWebSocket *sself, NSData *data) {
- __block frame_header header = {0};
-
- const uint8_t *headerBuffer = data.bytes;
- assert(data.length >= 2);
-
- if (headerBuffer[0] & SRRsvMask) {
- [sself _closeWithProtocolError:@"Server used RSV bits"];
- return;
- }
-
- uint8_t receivedOpcode = (SROpCodeMask & headerBuffer[0]);
-
- BOOL isControlFrame = (receivedOpcode == SROpCodePing || receivedOpcode == SROpCodePong || receivedOpcode == SROpCodeConnectionClose);
-
- if (!isControlFrame && receivedOpcode != 0 && sself->_currentFrameCount > 0) {
- [sself _closeWithProtocolError:@"all data frames after the initial data frame must have opcode 0"];
- return;
- }
-
- if (receivedOpcode == 0 && sself->_currentFrameCount == 0) {
- [sself _closeWithProtocolError:@"cannot continue a message"];
- return;
- }
-
- header.opcode = receivedOpcode == 0 ? sself->_currentFrameOpcode : receivedOpcode;
-
- header.fin = !!(SRFinMask & headerBuffer[0]);
-
-
- header.masked = !!(SRMaskMask & headerBuffer[1]);
- header.payload_length = SRPayloadLenMask & headerBuffer[1];
-
- headerBuffer = NULL;
-
- if (header.masked) {
- [sself _closeWithProtocolError:@"Client must receive unmasked data"];
- return;
- }
-
- size_t extra_bytes_needed = header.masked ? sizeof(sself->_currentReadMaskKey) : 0;
-
- if (header.payload_length == 126) {
- extra_bytes_needed += sizeof(uint16_t);
- } else if (header.payload_length == 127) {
- extra_bytes_needed += sizeof(uint64_t);
- }
-
- if (extra_bytes_needed == 0) {
- [sself _handleFrameHeader:header curData:sself->_currentFrameData];
- } else {
- [sself _addConsumerWithDataLength:extra_bytes_needed callback:^(SRWebSocket *eself, NSData *edata) {
- size_t mapped_size = edata.length;
-#pragma unused (mapped_size)
- const void *mapped_buffer = edata.bytes;
- size_t offset = 0;
-
- if (header.payload_length == 126) {
- assert(mapped_size >= sizeof(uint16_t));
- uint16_t payloadLength = 0;
- memcpy(&payloadLength, mapped_buffer, sizeof(uint16_t));
- payloadLength = CFSwapInt16BigToHost(payloadLength);
-
- header.payload_length = payloadLength;
- offset += sizeof(uint16_t);
- } else if (header.payload_length == 127) {
- assert(mapped_size >= sizeof(uint64_t));
- uint64_t payloadLength = 0;
- memcpy(&payloadLength, mapped_buffer, sizeof(uint64_t));
- payloadLength = CFSwapInt64BigToHost(payloadLength);
-
- header.payload_length = payloadLength;
- offset += sizeof(uint64_t);
- } else {
- assert(header.payload_length < 126 && header.payload_length >= 0);
- }
-
- if (header.masked) {
- assert(mapped_size >= sizeof(eself->_currentReadMaskOffset) + offset);
- memcpy(eself->_currentReadMaskKey, ((uint8_t *)mapped_buffer) + offset, sizeof(eself->_currentReadMaskKey));
- }
-
- [eself _handleFrameHeader:header curData:eself->_currentFrameData];
- } readToCurrentFrame:NO unmaskBytes:NO];
- }
- } readToCurrentFrame:NO unmaskBytes:NO];
-}
-
-- (void)_readFrameNew
-{
- dispatch_async(_workQueue, ^{
- // Don't reset the length, since Apple doesn't guarantee that this will free the memory (and in tests on
- // some platforms, it doesn't seem to, effectively causing a leak the size of the biggest frame so far).
- self->_currentFrameData = [[NSMutableData alloc] init];
-
- self->_currentFrameOpcode = 0;
- self->_currentFrameCount = 0;
- self->_readOpCount = 0;
- self->_currentStringScanPosition = 0;
-
- [self _readFrameContinue];
- });
-}
-
-- (void)_pumpWriting
-{
- [self assertOnWorkQueue];
-
- NSUInteger dataLength = dispatch_data_get_size(_outputBuffer);
- if (dataLength - _outputBufferOffset > 0 && _outputStream.hasSpaceAvailable) {
- __block NSInteger bytesWritten = 0;
- __block BOOL streamFailed = NO;
-
- dispatch_data_t dataToSend = dispatch_data_create_subrange(_outputBuffer, _outputBufferOffset, dataLength - _outputBufferOffset);
- dispatch_data_apply(dataToSend, ^bool(dispatch_data_t region, size_t offset, const void *buffer, size_t size) {
- NSInteger sentLength = [_outputStream write:buffer maxLength:size];
- if (sentLength == -1) {
- streamFailed = YES;
- return false;
- }
- bytesWritten += sentLength;
- return (sentLength >= (NSInteger)size); // If we can't write all the data into the stream - bail-out early.
- });
- if (streamFailed) {
- NSInteger code = 2145;
- NSString *description = @"Error writing to stream.";
- NSError *streamError = _outputStream.streamError;
- NSError *error = streamError ? SRErrorWithCodeDescriptionUnderlyingError(code, description, streamError) : SRErrorWithCodeDescription(code, description);
- [self _failWithError:error];
- return;
- }
-
- _outputBufferOffset += bytesWritten;
-
- if (_outputBufferOffset > SRDefaultBufferSize() && _outputBufferOffset > dataLength / 2) {
- _outputBuffer = dispatch_data_create_subrange(_outputBuffer, _outputBufferOffset, dataLength - _outputBufferOffset);
- _outputBufferOffset = 0;
- }
- }
-
- if (_closeWhenFinishedWriting &&
- (dispatch_data_get_size(_outputBuffer) - _outputBufferOffset) == 0 &&
- (_inputStream.streamStatus != NSStreamStatusNotOpen &&
- _inputStream.streamStatus != NSStreamStatusClosed) &&
- !_sentClose) {
- _sentClose = YES;
-
- @synchronized(self) {
- [_outputStream close];
- [_inputStream close];
-
-
- for (NSArray *runLoop in [_scheduledRunloops copy]) {
- [self unscheduleFromRunLoop:[runLoop objectAtIndex:0] forMode:[runLoop objectAtIndex:1]];
- }
- }
-
- if (!_failed) {
- [self.delegateController performDelegateBlock:^(id<SRWebSocketDelegate> _Nullable delegate, SRDelegateAvailableMethods availableMethods) {
- if (availableMethods.didCloseWithCode) {
- [delegate webSocket:self didCloseWithCode:self->_closeCode reason:self->_closeReason wasClean:YES];
- }
- }];
- }
-
- [self _scheduleCleanup];
- }
-}
-
-- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback
-{
- [self assertOnWorkQueue];
- [self _addConsumerWithScanner:consumer callback:callback dataLength:0];
-}
-
-- (void)_addConsumerWithDataLength:(size_t)dataLength callback:(data_callback)callback readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes
-{
- [self assertOnWorkQueue];
- assert(dataLength);
-
- [_consumers addObject:[_consumerPool consumerWithScanner:nil handler:callback bytesNeeded:dataLength readToCurrentFrame:readToCurrentFrame unmaskBytes:unmaskBytes]];
- [self _pumpScanner];
-}
-
-- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback dataLength:(size_t)dataLength
-{
- [self assertOnWorkQueue];
- [_consumers addObject:[_consumerPool consumerWithScanner:consumer handler:callback bytesNeeded:dataLength readToCurrentFrame:NO unmaskBytes:NO]];
- [self _pumpScanner];
-}
-
-
-- (void)_scheduleCleanup
-{
- @synchronized(self) {
- if (_cleanupScheduled) {
- return;
- }
-
- _cleanupScheduled = YES;
-
- // Cleanup NSStream delegate's in the same RunLoop used by the streams themselves:
- // This way we'll prevent race conditions between handleEvent and SRWebsocket's dealloc
- NSTimer *timer = [NSTimer timerWithTimeInterval:(0.0f) target:self selector:@selector(_cleanupSelfReference:) userInfo:nil repeats:NO];
- [[NSRunLoop SR_networkRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
- }
-}
-
-- (void)_cleanupSelfReference:(NSTimer *)timer
-{
- @synchronized(self) {
- // Nuke NSStream delegate's
- _inputStream.delegate = nil;
- _outputStream.delegate = nil;
-
- // Remove the streams, right now, from the networkRunLoop
- [_inputStream close];
- [_outputStream close];
- }
-
- // Cleanup selfRetain in the same GCD queue as usual
- dispatch_async(_workQueue, ^{
- self->_selfRetain = nil;
- });
-}
-
-
-static const char CRLFCRLFBytes[] = {'\r', '\n', '\r', '\n'};
-
-- (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler
-{
- [self _readUntilBytes:CRLFCRLFBytes length:sizeof(CRLFCRLFBytes) callback:dataHandler];
-}
-
-- (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler
-{
- // TODO optimize so this can continue from where we last searched
- stream_scanner consumer = ^size_t(NSData *data) {
- __block size_t found_size = 0;
- __block size_t match_count = 0;
-
- size_t size = data.length;
- const unsigned char *buffer = data.bytes;
- for (size_t i = 0; i < size; i++ ) {
- if (((const unsigned char *)buffer)[i] == ((const unsigned char *)bytes)[match_count]) {
- match_count += 1;
- if (match_count == length) {
- found_size = i + 1;
- break;
- }
- } else {
- match_count = 0;
- }
- }
- return found_size;
- };
- [self _addConsumerWithScanner:consumer callback:dataHandler];
-}
-
-
-// Returns true if did work
-- (BOOL)_innerPumpScanner {
-
- BOOL didWork = NO;
-
- if (self.readyState >= SR_CLOSED) {
- return didWork;
- }
-
- size_t readBufferSize = dispatch_data_get_size(_readBuffer);
-
- if (!_consumers.count) {
- return didWork;
- }
-
- size_t curSize = readBufferSize - _readBufferOffset;
- if (!curSize) {
- return didWork;
- }
-
- SRIOConsumer *consumer = [_consumers objectAtIndex:0];
-
- size_t bytesNeeded = consumer.bytesNeeded;
-
- size_t foundSize = 0;
- if (consumer.consumer) {
- NSData *subdata = (NSData *)dispatch_data_create_subrange(_readBuffer, _readBufferOffset, readBufferSize - _readBufferOffset);
- foundSize = consumer.consumer(subdata);
- } else {
- assert(consumer.bytesNeeded);
- if (curSize >= bytesNeeded) {
- foundSize = bytesNeeded;
- } else if (consumer.readToCurrentFrame) {
- foundSize = curSize;
- }
- }
-
- if (consumer.readToCurrentFrame || foundSize) {
- dispatch_data_t slice = dispatch_data_create_subrange(_readBuffer, _readBufferOffset, foundSize);
-
- _readBufferOffset += foundSize;
-
- if (_readBufferOffset > SRDefaultBufferSize() && _readBufferOffset > readBufferSize / 2) {
- _readBuffer = dispatch_data_create_subrange(_readBuffer, _readBufferOffset, readBufferSize - _readBufferOffset);
- _readBufferOffset = 0;
- }
-
- if (consumer.unmaskBytes) {
- __block NSMutableData *mutableSlice = [slice mutableCopy];
-
- NSUInteger len = mutableSlice.length;
- uint8_t *bytes = mutableSlice.mutableBytes;
-
- for (NSUInteger i = 0; i < len; i++) {
- bytes[i] = bytes[i] ^ _currentReadMaskKey[_currentReadMaskOffset % sizeof(_currentReadMaskKey)];
- _currentReadMaskOffset += 1;
- }
-
- slice = dispatch_data_create(bytes, len, nil, ^{
- mutableSlice = nil;
- });
- }
-
- if (consumer.readToCurrentFrame) {
- dispatch_data_apply(slice, ^bool(dispatch_data_t region, size_t offset, const void *buffer, size_t size) {
- [_currentFrameData appendBytes:buffer length:size];
- return true;
- });
-
- _readOpCount += 1;
-
- if (_currentFrameOpcode == SROpCodeTextFrame) {
- // Validate UTF8 stuff.
- size_t currentDataSize = _currentFrameData.length;
- if (_currentFrameOpcode == SROpCodeTextFrame && currentDataSize > 0) {
- // TODO: Optimize the crap out of this. Don't really have to copy all the data each time
-
- size_t scanSize = currentDataSize - _currentStringScanPosition;
-
- NSData *scan_data = [_currentFrameData subdataWithRange:NSMakeRange(_currentStringScanPosition, scanSize)];
- int32_t valid_utf8_size = validate_dispatch_data_partial_string(scan_data);
-
- if (valid_utf8_size == -1) {
- [self closeWithCode:SRStatusCodeInvalidUTF8 reason:@"Text frames must be valid UTF-8"];
- dispatch_async(_workQueue, ^{
- [self closeConnection];
- });
- return didWork;
- } else {
- _currentStringScanPosition += valid_utf8_size;
- }
- }
-
- }
-
- consumer.bytesNeeded -= foundSize;
-
- if (consumer.bytesNeeded == 0) {
- [_consumers removeObjectAtIndex:0];
- consumer.handler(self, nil);
- [_consumerPool returnConsumer:consumer];
- didWork = YES;
- }
- } else if (foundSize) {
- [_consumers removeObjectAtIndex:0];
- consumer.handler(self, (NSData *)slice);
- [_consumerPool returnConsumer:consumer];
- didWork = YES;
- }
- }
- return didWork;
-}
-
--(void)_pumpScanner
-{
- [self assertOnWorkQueue];
-
- if (!_isPumping) {
- _isPumping = YES;
- } else {
- return;
- }
-
- while ([self _innerPumpScanner]) {
-
- }
-
- _isPumping = NO;
-}
-
-//#define NOMASK
-
-static const size_t SRFrameHeaderOverhead = 32;
-
-- (void)_sendFrameWithOpcode:(SROpCode)opCode data:(NSData *)data
-{
- [self assertOnWorkQueue];
-
- if (!data) {
- return;
- }
-
- size_t payloadLength = data.length;
-
- NSMutableData *frameData = [[NSMutableData alloc] initWithLength:payloadLength + SRFrameHeaderOverhead];
- if (!frameData) {
- [self closeWithCode:SRStatusCodeMessageTooBig reason:@"Message too big"];
- return;
- }
- uint8_t *frameBuffer = (uint8_t *)frameData.mutableBytes;
-
- // set fin
- frameBuffer[0] = SRFinMask | opCode;
-
- // set the mask and header
- frameBuffer[1] |= SRMaskMask;
-
- size_t frameBufferSize = 2;
-
- if (payloadLength < 126) {
- frameBuffer[1] |= payloadLength;
- } else {
- uint64_t declaredPayloadLength = 0;
- size_t declaredPayloadLengthSize = 0;
-
- if (payloadLength <= UINT16_MAX) {
- frameBuffer[1] |= 126;
-
- declaredPayloadLength = CFSwapInt16BigToHost((uint16_t)payloadLength);
- declaredPayloadLengthSize = sizeof(uint16_t);
- } else {
- frameBuffer[1] |= 127;
-
- declaredPayloadLength = CFSwapInt64BigToHost((uint64_t)payloadLength);
- declaredPayloadLengthSize = sizeof(uint64_t);
- }
-
- memcpy((frameBuffer + frameBufferSize), &declaredPayloadLength, declaredPayloadLengthSize);
- frameBufferSize += declaredPayloadLengthSize;
- }
-
- const uint8_t *unmaskedPayloadBuffer = (uint8_t *)data.bytes;
- uint8_t *maskKey = frameBuffer + frameBufferSize;
-
- size_t randomBytesSize = sizeof(uint32_t);
- NSData *randomData = SRRandomData(randomBytesSize);
- [randomData getBytes:maskKey range:NSMakeRange(0, randomBytesSize)];
- frameBufferSize += randomBytesSize;
-
- // Copy and unmask the buffer
- uint8_t *frameBufferPayloadPointer = frameBuffer + frameBufferSize;
-
- memcpy(frameBufferPayloadPointer, unmaskedPayloadBuffer, payloadLength);
- SRMaskBytesSIMD(frameBufferPayloadPointer, payloadLength, maskKey);
- frameBufferSize += payloadLength;
-
- assert(frameBufferSize <= frameData.length);
- frameData.length = frameBufferSize;
-
- [self _writeData:frameData];
-}
-
-- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
-{
- __weak typeof(self) wself = self;
-
- if (_requestRequiresSSL && !_streamSecurityValidated &&
- (eventCode == NSStreamEventHasBytesAvailable || eventCode == NSStreamEventHasSpaceAvailable)) {
- SecTrustRef trust = (__bridge SecTrustRef)[aStream propertyForKey:(__bridge id)kCFStreamPropertySSLPeerTrust];
- if (trust) {
- NSString *const host = _urlRequest.URL.host;
- if (!host || host.length == 0) {
- dispatch_async(_workQueue, ^{
- NSError *error = SRErrorWithDomainCodeDescription(NSURLErrorDomain,
- NSURLErrorBadURL,
- @"Unable to validate certificate for empty host.");
- [wself _failWithError:error];
- });
- return;
- }
- _streamSecurityValidated = [_securityPolicy evaluateServerTrust:trust forDomain:host];
- }
- if (!_streamSecurityValidated) {
- dispatch_async(_workQueue, ^{
- NSError *error = SRErrorWithDomainCodeDescription(NSURLErrorDomain,
- NSURLErrorClientCertificateRejected,
- @"Invalid server certificate.");
- [wself _failWithError:error];
- });
- return;
- }
- dispatch_async(_workQueue, ^{
- [self didConnect];
- });
- }
- dispatch_async(_workQueue, ^{
- [wself safeHandleEvent:eventCode stream:aStream];
- });
-}
-
-- (void)safeHandleEvent:(NSStreamEvent)eventCode stream:(NSStream *)aStream
-{
- switch (eventCode) {
- case NSStreamEventOpenCompleted: {
- SRDebugLog(@"NSStreamEventOpenCompleted %@", aStream);
- if (self.readyState >= SR_CLOSING) {
- return;
- }
- assert(_readBuffer);
-
- if (!_requestRequiresSSL && self.readyState == SR_CONNECTING && aStream == _inputStream) {
- [self didConnect];
- }
-
- [self _pumpWriting];
- [self _pumpScanner];
-
- break;
- }
-
- case NSStreamEventErrorOccurred: {
- SRDebugLog(@"NSStreamEventErrorOccurred %@ %@", aStream, [[aStream streamError] copy]);
- /// TODO specify error better!
- [self _failWithError:aStream.streamError];
- _readBufferOffset = 0;
- _readBuffer = dispatch_data_empty;
- break;
-
- }
-
- case NSStreamEventEndEncountered: {
- [self _pumpScanner];
- SRDebugLog(@"NSStreamEventEndEncountered %@", aStream);
- if (aStream.streamError) {
- [self _failWithError:aStream.streamError];
- } else {
- dispatch_async(_workQueue, ^{
- if (self.readyState != SR_CLOSED) {
- self.readyState = SR_CLOSED;
- [self _scheduleCleanup];
- }
-
- if (!self->_sentClose && !self->_failed) {
- self->_sentClose = YES;
- // If we get closed in this state it's probably not clean because we should be sending this when we send messages
- [self.delegateController performDelegateBlock:^(id<SRWebSocketDelegate> _Nullable delegate, SRDelegateAvailableMethods availableMethods) {
- if (availableMethods.didCloseWithCode) {
- [delegate webSocket:self
- didCloseWithCode:SRStatusCodeGoingAway
- reason:@"Stream end encountered"
- wasClean:NO];
- }
- }];
- }
- });
- }
-
- break;
- }
-
- case NSStreamEventHasBytesAvailable: {
- SRDebugLog(@"NSStreamEventHasBytesAvailable %@", aStream);
- uint8_t buffer[SRDefaultBufferSize()];
-
- while (_inputStream.hasBytesAvailable) {
- NSInteger bytesRead = [_inputStream read:buffer maxLength:SRDefaultBufferSize()];
- if (bytesRead > 0) {
- dispatch_data_t data = dispatch_data_create(buffer, bytesRead, nil, DISPATCH_DATA_DESTRUCTOR_DEFAULT);
- if (!data) {
- NSError *error = SRErrorWithCodeDescription(SRStatusCodeMessageTooBig,
- @"Unable to allocate memory to read from socket.");
- [self _failWithError:error];
- return;
- }
- _readBuffer = dispatch_data_create_concat(_readBuffer, data);
- } else if (bytesRead == -1) {
- [self _failWithError:_inputStream.streamError];
- }
- }
- [self _pumpScanner];
- break;
- }
-
- case NSStreamEventHasSpaceAvailable: {
- SRDebugLog(@"NSStreamEventHasSpaceAvailable %@", aStream);
- [self _pumpWriting];
- break;
- }
-
- case NSStreamEventNone:
- SRDebugLog(@"(default) %@", aStream);
- break;
- }
-}
-
-///--------------------------------------
-#pragma mark - Delegate
-///--------------------------------------
-
-- (id<SRWebSocketDelegate> _Nullable)delegate
-{
- return self.delegateController.delegate;
-}
-
-- (void)setDelegate:(id<SRWebSocketDelegate> _Nullable)delegate
-{
- self.delegateController.delegate = delegate;
-}
-
-- (void)setDelegateDispatchQueue:(dispatch_queue_t _Nullable)queue
-{
- self.delegateController.dispatchQueue = queue;
-}
-
-- (dispatch_queue_t _Nullable)delegateDispatchQueue
-{
- return self.delegateController.dispatchQueue;
-}
-
-- (void)setDelegateOperationQueue:(NSOperationQueue *_Nullable)queue
-{
- self.delegateController.operationQueue = queue;
-}
-
-- (NSOperationQueue *_Nullable)delegateOperationQueue
-{
- return self.delegateController.operationQueue;
-}
-
-@end
-
-#ifdef HAS_ICU
-
-static inline int32_t validate_dispatch_data_partial_string(NSData *data) {
- if ([data length] > INT32_MAX) {
- // INT32_MAX is the limit so long as this Framework is using 32 bit ints everywhere.
- return -1;
- }
-
- int32_t size = (int32_t)[data length];
-
- const void * contents = [data bytes];
- const uint8_t *str = (const uint8_t *)contents;
-
- UChar32 codepoint = 1;
- int32_t offset = 0;
- int32_t lastOffset = 0;
- while(offset < size && codepoint > 0) {
- lastOffset = offset;
- U8_NEXT(str, offset, size, codepoint);
- }
-
- if (codepoint == -1) {
- // Check to see if the last byte is valid or whether it was just continuing
- if (!U8_IS_LEAD(str[lastOffset]) || U8_COUNT_TRAIL_BYTES(str[lastOffset]) + lastOffset < (int32_t)size) {
-
- size = -1;
- } else {
- uint8_t leadByte = str[lastOffset];
- U8_MASK_LEAD_BYTE(leadByte, U8_COUNT_TRAIL_BYTES(leadByte));
-
- for (int i = lastOffset + 1; i < offset; i++) {
- if (U8_IS_SINGLE(str[i]) || U8_IS_LEAD(str[i]) || !U8_IS_TRAIL(str[i])) {
- size = -1;
- }
- }
-
- if (size != -1) {
- size = lastOffset;
- }
- }
- }
-
- if (size != -1 && ![[NSString alloc] initWithBytesNoCopy:(char *)[data bytes] length:size encoding:NSUTF8StringEncoding freeWhenDone:NO]) {
- size = -1;
- }
-
- return size;
-}
-
-#else
-
-// This is a hack, and probably not optimal
-static inline int32_t validate_dispatch_data_partial_string(NSData *data) {
- static const int maxCodepointSize = 3;
-
- for (int i = 0; i < maxCodepointSize; i++) {
- NSString *str = [[NSString alloc] initWithBytesNoCopy:(char *)data.bytes length:data.length - i encoding:NSUTF8StringEncoding freeWhenDone:NO];
- if (str) {
- return (int32_t)data.length - i;
- }
- }
-
- return -1;
-}
-
-#endif
+++ /dev/null
-//
-// Copyright 2012 Square Inc.
-// Portions Copyright (c) 2016-present, Facebook, Inc.
-//
-// All rights reserved.
-//
-// This source code is licensed under the BSD-style license found in the
-// LICENSE file in the root directory of this source tree. An additional grant
-// of patent rights can be found in the PATENTS file in the same directory.
-//
-
-#import <SocketRocket/NSRunLoop+SRWebSocket.h>
-#import <SocketRocket/NSURLRequest+SRWebSocket.h>
-#import <SocketRocket/SRSecurityPolicy.h>
-#import <SocketRocket/SRWebSocket.h>
+++ /dev/null
-<?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>${PODS_DEVELOPMENT_LANGUAGE}</string>
- <key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
- <key>CFBundleIdentifier</key>
- <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundlePackageType</key>
- <string>FMWK</string>
- <key>CFBundleShortVersionString</key>
- <string>1.0.0</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>${CURRENT_PROJECT_VERSION}</string>
- <key>NSPrincipalClass</key>
- <string></string>
-</dict>
-</plist>
+++ /dev/null
-# Acknowledgements
-This application makes use of the following third party libraries:
-
-## SVProgressHUD
-
-MIT License
-
-Copyright (c) 2011-2023 Sam Vermette, Tobias Totzek and contributors.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-
-## SnapKit
-
-Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
-
-## SocketRocket
-
-BSD License
-
-For SocketRocket software
-
-Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- * Neither the name Facebook nor the names of its contributors may be used to
- endorse or promote products derived from this software without specific
- prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-Generated by CocoaPods - https://cocoapods.org
+++ /dev/null
-<?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>PreferenceSpecifiers</key>
- <array>
- <dict>
- <key>FooterText</key>
- <string>This application makes use of the following third party libraries:</string>
- <key>Title</key>
- <string>Acknowledgements</string>
- <key>Type</key>
- <string>PSGroupSpecifier</string>
- </dict>
- <dict>
- <key>FooterText</key>
- <string>MIT License
-
-Copyright (c) 2011-2023 Sam Vermette, Tobias Totzek and contributors.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-</string>
- <key>License</key>
- <string>MIT</string>
- <key>Title</key>
- <string>SVProgressHUD</string>
- <key>Type</key>
- <string>PSGroupSpecifier</string>
- </dict>
- <dict>
- <key>FooterText</key>
- <string>Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-</string>
- <key>License</key>
- <string>MIT</string>
- <key>Title</key>
- <string>SnapKit</string>
- <key>Type</key>
- <string>PSGroupSpecifier</string>
- </dict>
- <dict>
- <key>FooterText</key>
- <string>BSD License
-
-For SocketRocket software
-
-Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- * Neither the name Facebook nor the names of its contributors may be used to
- endorse or promote products derived from this software without specific
- prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</string>
- <key>License</key>
- <string>BSD</string>
- <key>Title</key>
- <string>SocketRocket</string>
- <key>Type</key>
- <string>PSGroupSpecifier</string>
- </dict>
- <dict>
- <key>FooterText</key>
- <string>Generated by CocoaPods - https://cocoapods.org</string>
- <key>Title</key>
- <string></string>
- <key>Type</key>
- <string>PSGroupSpecifier</string>
- </dict>
- </array>
- <key>StringsTable</key>
- <string>Acknowledgements</string>
- <key>Title</key>
- <string>Acknowledgements</string>
-</dict>
-</plist>
+++ /dev/null
-#import <Foundation/Foundation.h>
-@interface PodsDummy_Pods_JoyGemAIDemo : NSObject
-@end
-@implementation PodsDummy_Pods_JoyGemAIDemo
-@end
+++ /dev/null
-${PODS_ROOT}/Target Support Files/Pods-JoyGemAIDemo/Pods-JoyGemAIDemo-frameworks.sh
-${BUILT_PRODUCTS_DIR}/SVProgressHUD/SVProgressHUD.framework
-${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework
-${BUILT_PRODUCTS_DIR}/SocketRocket/SocketRocket.framework
\ No newline at end of file
+++ /dev/null
-${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SVProgressHUD.framework
-${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework
-${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SocketRocket.framework
\ No newline at end of file
+++ /dev/null
-${PODS_ROOT}/Target Support Files/Pods-JoyGemAIDemo/Pods-JoyGemAIDemo-frameworks.sh
-${BUILT_PRODUCTS_DIR}/SVProgressHUD/SVProgressHUD.framework
-${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework
-${BUILT_PRODUCTS_DIR}/SocketRocket/SocketRocket.framework
\ No newline at end of file
+++ /dev/null
-${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SVProgressHUD.framework
-${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SnapKit.framework
-${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SocketRocket.framework
\ No newline at end of file
+++ /dev/null
-#!/bin/sh
-set -e
-set -u
-set -o pipefail
-
-function on_error {
- echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
-}
-trap 'on_error $LINENO' ERR
-
-if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
- # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
- # frameworks to, so exit 0 (signalling the script phase was successful).
- exit 0
-fi
-
-echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
-mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
-
-COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
-SWIFT_STDLIB_PATH="${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
-BCSYMBOLMAP_DIR="BCSymbolMaps"
-
-
-# This protects against multiple targets copying the same framework dependency at the same time. The solution
-# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
-RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
-
-# Copies and strips a vendored framework
-install_framework()
-{
- if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
- local source="${BUILT_PRODUCTS_DIR}/$1"
- elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
- local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
- elif [ -r "$1" ]; then
- local source="$1"
- fi
-
- local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
-
- if [ -L "${source}" ]; then
- echo "Symlinked..."
- source="$(readlink -f "${source}")"
- fi
-
- if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
- # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied
- find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do
- echo "Installing $f"
- install_bcsymbolmap "$f" "$destination"
- rm "$f"
- done
- rmdir "${source}/${BCSYMBOLMAP_DIR}"
- fi
-
- # Use filter instead of exclude so missing patterns don't throw errors.
- echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
- rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
-
- local basename
- basename="$(basename -s .framework "$1")"
- binary="${destination}/${basename}.framework/${basename}"
-
- if ! [ -r "$binary" ]; then
- binary="${destination}/${basename}"
- elif [ -L "${binary}" ]; then
- echo "Destination binary is symlinked..."
- dirname="$(dirname "${binary}")"
- binary="${dirname}/$(readlink "${binary}")"
- fi
-
- # Strip invalid architectures so "fat" simulator / device frameworks work on device
- if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
- strip_invalid_archs "$binary"
- fi
-
- # Resign the code if required by the build settings to avoid unstable apps
- code_sign_if_enabled "${destination}/$(basename "$1")"
-
- # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
- if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
- local swift_runtime_libs
- swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
- for lib in $swift_runtime_libs; do
- echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
- rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
- code_sign_if_enabled "${destination}/${lib}"
- done
- fi
-}
-# Copies and strips a vendored dSYM
-install_dsym() {
- local source="$1"
- warn_missing_arch=${2:-true}
- if [ -r "$source" ]; then
- # Copy the dSYM into the targets temp dir.
- echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
- rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
-
- local basename
- basename="$(basename -s .dSYM "$source")"
- binary_name="$(ls "$source/Contents/Resources/DWARF")"
- binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
-
- # Strip invalid architectures from the dSYM.
- if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
- strip_invalid_archs "$binary" "$warn_missing_arch"
- fi
- if [[ $STRIP_BINARY_RETVAL == 0 ]]; then
- # Move the stripped file into its final destination.
- echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
- rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
- else
- # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
- mkdir -p "${DWARF_DSYM_FOLDER_PATH}"
- touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
- fi
- fi
-}
-
-# Used as a return value for each invocation of `strip_invalid_archs` function.
-STRIP_BINARY_RETVAL=0
-
-# Strip invalid architectures
-strip_invalid_archs() {
- binary="$1"
- warn_missing_arch=${2:-true}
- # Get architectures for current target binary
- binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
- # Intersect them with the architectures we are building for
- intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
- # If there are no archs supported by this binary then warn the user
- if [[ -z "$intersected_archs" ]]; then
- if [[ "$warn_missing_arch" == "true" ]]; then
- echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
- fi
- STRIP_BINARY_RETVAL=1
- return
- fi
- stripped=""
- for arch in $binary_archs; do
- if ! [[ "${ARCHS}" == *"$arch"* ]]; then
- # Strip non-valid architectures in-place
- lipo -remove "$arch" -output "$binary" "$binary"
- stripped="$stripped $arch"
- fi
- done
- if [[ "$stripped" ]]; then
- echo "Stripped $binary of architectures:$stripped"
- fi
- STRIP_BINARY_RETVAL=0
-}
-
-# Copies the bcsymbolmap files of a vendored framework
-install_bcsymbolmap() {
- local bcsymbolmap_path="$1"
- local destination="${BUILT_PRODUCTS_DIR}"
- echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
- rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
-}
-
-# Signs a framework with the provided identity
-code_sign_if_enabled() {
- if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
- # Use the current code_sign_identity
- echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
- local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
-
- if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
- code_sign_cmd="$code_sign_cmd &"
- fi
- echo "$code_sign_cmd"
- eval "$code_sign_cmd"
- fi
-}
-
-if [[ "$CONFIGURATION" == "Debug" ]]; then
- install_framework "${BUILT_PRODUCTS_DIR}/SVProgressHUD/SVProgressHUD.framework"
- install_framework "${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework"
- install_framework "${BUILT_PRODUCTS_DIR}/SocketRocket/SocketRocket.framework"
-fi
-if [[ "$CONFIGURATION" == "Release" ]]; then
- install_framework "${BUILT_PRODUCTS_DIR}/SVProgressHUD/SVProgressHUD.framework"
- install_framework "${BUILT_PRODUCTS_DIR}/SnapKit/SnapKit.framework"
- install_framework "${BUILT_PRODUCTS_DIR}/SocketRocket/SocketRocket.framework"
-fi
-if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
- wait
-fi
+++ /dev/null
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#else
-#ifndef FOUNDATION_EXPORT
-#if defined(__cplusplus)
-#define FOUNDATION_EXPORT extern "C"
-#else
-#define FOUNDATION_EXPORT extern
-#endif
-#endif
-#endif
-
-
-FOUNDATION_EXPORT double Pods_JoyGemAIDemoVersionNumber;
-FOUNDATION_EXPORT const unsigned char Pods_JoyGemAIDemoVersionString[];
-
+++ /dev/null
-ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
-CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
-FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SVProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket"
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SVProgressHUD/SVProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket/SocketRocket.framework/Headers"
-LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
-LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift $(SDKROOT)/usr/lib/swift
-OTHER_LDFLAGS = $(inherited) -l"icucore" -l"swiftCoreGraphics" -framework "CFNetwork" -framework "QuartzCore" -framework "SVProgressHUD" -framework "Security" -framework "SnapKit" -framework "SocketRocket"
-OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/SVProgressHUD" "-F${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "-F${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket"
-OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
-PODS_BUILD_DIR = ${BUILD_DIR}
-PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
-PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
-PODS_ROOT = ${SRCROOT}/Pods
-PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
-USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
+++ /dev/null
-framework module Pods_JoyGemAIDemo {
- umbrella header "Pods-JoyGemAIDemo-umbrella.h"
-
- export *
- module * { export * }
-}
+++ /dev/null
-ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
-CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
-FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SVProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket"
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/SVProgressHUD/SVProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket/SocketRocket.framework/Headers"
-LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
-LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift $(SDKROOT)/usr/lib/swift
-OTHER_LDFLAGS = $(inherited) -l"icucore" -l"swiftCoreGraphics" -framework "CFNetwork" -framework "QuartzCore" -framework "SVProgressHUD" -framework "Security" -framework "SnapKit" -framework "SocketRocket"
-OTHER_MODULE_VERIFIER_FLAGS = $(inherited) "-F${PODS_CONFIGURATION_BUILD_DIR}/SVProgressHUD" "-F${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" "-F${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket"
-OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
-PODS_BUILD_DIR = ${BUILD_DIR}
-PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
-PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
-PODS_ROOT = ${SRCROOT}/Pods
-PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
-USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
+++ /dev/null
-<?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>${PODS_DEVELOPMENT_LANGUAGE}</string>
- <key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
- <key>CFBundleIdentifier</key>
- <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundlePackageType</key>
- <string>FMWK</string>
- <key>CFBundleShortVersionString</key>
- <string>2.3.1</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>${CURRENT_PROJECT_VERSION}</string>
- <key>NSPrincipalClass</key>
- <string></string>
-</dict>
-</plist>
+++ /dev/null
-#import <Foundation/Foundation.h>
-@interface PodsDummy_SVProgressHUD : NSObject
-@end
-@implementation PodsDummy_SVProgressHUD
-@end
+++ /dev/null
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#else
-#ifndef FOUNDATION_EXPORT
-#if defined(__cplusplus)
-#define FOUNDATION_EXPORT extern "C"
-#else
-#define FOUNDATION_EXPORT extern
-#endif
-#endif
-#endif
-
+++ /dev/null
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#else
-#ifndef FOUNDATION_EXPORT
-#if defined(__cplusplus)
-#define FOUNDATION_EXPORT extern "C"
-#else
-#define FOUNDATION_EXPORT extern
-#endif
-#endif
-#endif
-
-#import "SVIndefiniteAnimatedView.h"
-#import "SVProgressAnimatedView.h"
-#import "SVProgressHUD.h"
-#import "SVRadialGradientLayer.h"
-
-FOUNDATION_EXPORT double SVProgressHUDVersionNumber;
-FOUNDATION_EXPORT const unsigned char SVProgressHUDVersionString[];
-
+++ /dev/null
-CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
-CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SVProgressHUD
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-OTHER_LDFLAGS = $(inherited) -framework "QuartzCore"
-PODS_BUILD_DIR = ${BUILD_DIR}
-PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
-PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
-PODS_ROOT = ${SRCROOT}
-PODS_TARGET_SRCROOT = ${PODS_ROOT}/SVProgressHUD
-PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
-PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
-SKIP_INSTALL = YES
-USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
+++ /dev/null
-framework module SVProgressHUD {
- umbrella header "SVProgressHUD-umbrella.h"
-
- export *
- module * { export * }
-}
+++ /dev/null
-CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
-CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SVProgressHUD
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-OTHER_LDFLAGS = $(inherited) -framework "QuartzCore"
-PODS_BUILD_DIR = ${BUILD_DIR}
-PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
-PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
-PODS_ROOT = ${SRCROOT}
-PODS_TARGET_SRCROOT = ${PODS_ROOT}/SVProgressHUD
-PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
-PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
-SKIP_INSTALL = YES
-USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
+++ /dev/null
-<?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>${PODS_DEVELOPMENT_LANGUAGE}</string>
- <key>CFBundleIdentifier</key>
- <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundlePackageType</key>
- <string>BNDL</string>
- <key>CFBundleShortVersionString</key>
- <string>5.7.1</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>1</string>
- <key>NSPrincipalClass</key>
- <string></string>
-</dict>
-</plist>
+++ /dev/null
-<?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>${PODS_DEVELOPMENT_LANGUAGE}</string>
- <key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
- <key>CFBundleIdentifier</key>
- <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundlePackageType</key>
- <string>FMWK</string>
- <key>CFBundleShortVersionString</key>
- <string>5.7.1</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>${CURRENT_PROJECT_VERSION}</string>
- <key>NSPrincipalClass</key>
- <string></string>
-</dict>
-</plist>
+++ /dev/null
-#import <Foundation/Foundation.h>
-@interface PodsDummy_SnapKit : NSObject
-@end
-@implementation PodsDummy_SnapKit
-@end
+++ /dev/null
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#else
-#ifndef FOUNDATION_EXPORT
-#if defined(__cplusplus)
-#define FOUNDATION_EXPORT extern "C"
-#else
-#define FOUNDATION_EXPORT extern
-#endif
-#endif
-#endif
-
+++ /dev/null
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#else
-#ifndef FOUNDATION_EXPORT
-#if defined(__cplusplus)
-#define FOUNDATION_EXPORT extern "C"
-#else
-#define FOUNDATION_EXPORT extern
-#endif
-#endif
-#endif
-
-
-FOUNDATION_EXPORT double SnapKitVersionNumber;
-FOUNDATION_EXPORT const unsigned char SnapKitVersionString[];
-
+++ /dev/null
-CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
-CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SnapKit
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift $(SDKROOT)/usr/lib/swift
-OTHER_LDFLAGS = $(inherited) -l"swiftCoreGraphics"
-OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
-PODS_BUILD_DIR = ${BUILD_DIR}
-PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
-PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
-PODS_ROOT = ${SRCROOT}
-PODS_TARGET_SRCROOT = ${PODS_ROOT}/SnapKit
-PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
-PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
-SKIP_INSTALL = YES
-USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
+++ /dev/null
-framework module SnapKit {
- umbrella header "SnapKit-umbrella.h"
-
- export *
- module * { export * }
-}
+++ /dev/null
-CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
-CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SnapKit
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift $(SDKROOT)/usr/lib/swift
-OTHER_LDFLAGS = $(inherited) -l"swiftCoreGraphics"
-OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
-PODS_BUILD_DIR = ${BUILD_DIR}
-PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
-PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
-PODS_ROOT = ${SRCROOT}
-PODS_TARGET_SRCROOT = ${PODS_ROOT}/SnapKit
-PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
-PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
-SKIP_INSTALL = YES
-USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
+++ /dev/null
-<?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>${PODS_DEVELOPMENT_LANGUAGE}</string>
- <key>CFBundleExecutable</key>
- <string>${EXECUTABLE_NAME}</string>
- <key>CFBundleIdentifier</key>
- <string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
- <key>CFBundleInfoDictionaryVersion</key>
- <string>6.0</string>
- <key>CFBundleName</key>
- <string>${PRODUCT_NAME}</string>
- <key>CFBundlePackageType</key>
- <string>FMWK</string>
- <key>CFBundleShortVersionString</key>
- <string>0.7.1</string>
- <key>CFBundleSignature</key>
- <string>????</string>
- <key>CFBundleVersion</key>
- <string>${CURRENT_PROJECT_VERSION}</string>
- <key>NSPrincipalClass</key>
- <string></string>
-</dict>
-</plist>
+++ /dev/null
-#import <Foundation/Foundation.h>
-@interface PodsDummy_SocketRocket : NSObject
-@end
-@implementation PodsDummy_SocketRocket
-@end
+++ /dev/null
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#else
-#ifndef FOUNDATION_EXPORT
-#if defined(__cplusplus)
-#define FOUNDATION_EXPORT extern "C"
-#else
-#define FOUNDATION_EXPORT extern
-#endif
-#endif
-#endif
-
+++ /dev/null
-#ifdef __OBJC__
-#import <UIKit/UIKit.h>
-#else
-#ifndef FOUNDATION_EXPORT
-#if defined(__cplusplus)
-#define FOUNDATION_EXPORT extern "C"
-#else
-#define FOUNDATION_EXPORT extern
-#endif
-#endif
-#endif
-
-#import "NSRunLoop+SRWebSocket.h"
-#import "NSURLRequest+SRWebSocket.h"
-#import "SocketRocket.h"
-#import "SRSecurityPolicy.h"
-#import "SRWebSocket.h"
-
-FOUNDATION_EXPORT double SocketRocketVersionNumber;
-FOUNDATION_EXPORT const unsigned char SocketRocketVersionString[];
-
+++ /dev/null
-CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
-CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-OTHER_LDFLAGS = $(inherited) -l"icucore" -framework "CFNetwork" -framework "Security"
-PODS_BUILD_DIR = ${BUILD_DIR}
-PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
-PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
-PODS_ROOT = ${SRCROOT}
-PODS_TARGET_SRCROOT = ${PODS_ROOT}/SocketRocket
-PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
-PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
-SKIP_INSTALL = YES
-USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
+++ /dev/null
-framework module SocketRocket {
- umbrella header "SocketRocket-umbrella.h"
-
- export *
- module * { export * }
-}
+++ /dev/null
-CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
-CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SocketRocket
-GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
-OTHER_LDFLAGS = $(inherited) -l"icucore" -framework "CFNetwork" -framework "Security"
-PODS_BUILD_DIR = ${BUILD_DIR}
-PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
-PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
-PODS_ROOT = ${SRCROOT}
-PODS_TARGET_SRCROOT = ${PODS_ROOT}/SocketRocket
-PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
-PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
-SKIP_INSTALL = YES
-USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
+++ /dev/null
-# source 'https://kkgithub.com/CocoaPods/Specs.git'
-source "https://gitee.com/mirrors/CocoaPods-Specs.git"
-platform :ios, '13.0'
-use_frameworks!
-
-target 'JoyGemAIDemo' do
- pod 'SnapKit', '~> 5.7.0'
- pod 'SVProgressHUD'
- #pod 'SocketRocket'
-end
#if 0
#elif defined(__arm64__) && __arm64__
-// Generated by Apple Swift version 6.0.2 effective-5.10 (swiftlang-6.0.2.1.2 clang-1600.0.26.4)
+// Generated by Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
#ifndef JOYGEMAI_SWIFT_H
#define JOYGEMAI_SWIFT_H
#pragma clang diagnostic push
/// 初始化sdk
- (void)initSdk;
+/// 初始化sdk
+/// - Parameter projectID: 可选方法
+- (void)initSdk:(nullable NSString*)projectID;
+
/// 日志打印级别
/// - Parameter level: 日志等级 分为关闭,简略,完全
- (void)setLogMode:(JoyGemLogMode)mode;
/// - speed: 默认1.0,范围[0.8,2]
-(void)setTtsSpeed:(float)speed;
+/// 配置测试环境
+/// - Parameters:
+/// - info: 测试环境字典
+-(void)setDebugEnvironment:(NSDictionary*)info;
+
@end
NS_ASSUME_NONNULL_END
///AI语音接收
/// - Parameters:
/// - data: 音频数据 pcm格式
--(void)chatManager:(JoyGemChatManager*)manager audioData:(nullable NSData*)data finish:(BOOL)isFinish;
+/// - index: 语句ID
+/// - sampleRate: 采样率
+/// - finish: 该句是否结束
+-(void)chatManager:(JoyGemChatManager*)manager audioData:(nullable NSData*)data index:(NSUInteger)index sampleRate:(NSUInteger)sampleRate finish:(BOOL)isFinish;
///用户语音识别
/// - Parameters:
/// - mode:错误代码
-(void)chatManager:(JoyGemChatManager*)manager onError:(JoyGemErrorCode)code;
+@optional
+-(void)chatManagerStopped:(JoyGemChatManager*)manager DEPRECATED_MSG_ATTRIBUTE("Use isActive");
+
@end
//AI对话的管理类
/// - custom: 自定义EQ类型
-(void)getCustomEQ:(void (^)(JoyGemCustomEQ*))custom error:(void (^)( NSError * _Nullable err))error;
-
/// 查找耳机
/// - Parameters:
/// - mode: 查找耳机命令类型
-(void)findHeadphone:(JoyGemFindHeadphoneMode)mode callback:(void (^)( NSError * _Nullable err))error;
+/// 获取设备DN码
+/// - Parameters:
+/// - dn: 设备DN,取不到则返回空值
+-(void)getDN:(void (^)(NSString*))dn error:(void (^)( NSError * _Nullable err))error;
@end
// swift-interface-format-version: 1.0
-// swift-compiler-version: Apple Swift version 6.0.2 effective-5.10 (swiftlang-6.0.2.1.2 clang-1600.0.26.4)
+// swift-compiler-version: Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
// swift-module-flags: -target arm64-apple-ios13.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -enable-bare-slash-regex -module-name JoyGemAI
// swift-module-flags-ignorable: -no-verify-emitted-module-interface
import Foundation
// swift-interface-format-version: 1.0
-// swift-compiler-version: Apple Swift version 6.0.2 effective-5.10 (swiftlang-6.0.2.1.2 clang-1600.0.26.4)
+// swift-compiler-version: Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
// swift-module-flags: -target arm64-apple-ios13.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -enable-bare-slash-regex -module-name JoyGemAI
// swift-module-flags-ignorable: -no-verify-emitted-module-interface
import Foundation
<dict>
<key>Headers/JoyGemAI-Swift.h</key>
<data>
- EzwLstWsXu+VfPMQanIZDbX3a0E=
+ okSjIYqQdjYFuhBqjGvwfYh8+aU=
</data>
<key>Headers/JoyGemAI.h</key>
<data>
</data>
<key>Headers/JoyGemAIManager.h</key>
<data>
- Oq+OIkczOsgav5Qo1BqTz/1gc4M=
+ D/pnfOpF7qKhUfhoTsKEfdEQQRQ=
</data>
<key>Headers/JoyGemCallManager.h</key>
<data>
</data>
<key>Headers/JoyGemChatManager.h</key>
<data>
- EOl/+6HcGPZVHgre1chnDptuCBU=
+ I9SSrf6xzcSE2qKnMMmiSe9IV1I=
</data>
<key>Headers/JoyGemDeviceManager.h</key>
<data>
- h7T4t0GUmAg2ZHyPU+Sn7lQrkw0=
+ GnuSbYAD+3F7R21VuV35n97Bubk=
</data>
<key>Headers/JoyGemEnum.h</key>
<data>
</data>
<key>Info.plist</key>
<data>
- vHVrQqK4ReuQBxyUxqv5BOG8mbw=
+ yyyfSn0pDOYFx2gtlmBDVpKhVxw=
</data>
<key>Modules/JoyGemAI.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo</key>
<data>
- jacBwduET4BLcaiJtoJ9sWWXQ6s=
+ CPeqh4HaaR/F9LP2LFiPwE3Qxzo=
</data>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.abi.json</key>
<data>
</data>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.private.swiftinterface</key>
<data>
- BmjRZIKCen7GN8lmcoDVw3R2KvM=
+ sOTjmG3OZu9FvWVYyTuqSix+tzU=
</data>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftdoc</key>
<data>
- xFskxbeAbkxTqKE8F2wcvY/ElFM=
+ s/YEyU+lH4pYoG62jihLM2SJPTU=
</data>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftinterface</key>
<data>
- BmjRZIKCen7GN8lmcoDVw3R2KvM=
+ sOTjmG3OZu9FvWVYyTuqSix+tzU=
</data>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftmodule</key>
<data>
- 4QozN8a+2xPGGnyDrUz/2Hg7JPI=
+ OKLv2mrRkW9EiT9AdyIjFh6WmI8=
</data>
<key>Modules/module.modulemap</key>
<data>
<dict>
<key>hash2</key>
<data>
- D6FOg3LxVu6AQ3xMxdtxm8TsqeXBLCKYS1SQ1weJXno=
+ Jktn0pvS86rbDKXpgT8xSUtpGRzWvf2yzqxwqMqFKS4=
</data>
</dict>
<key>Headers/JoyGemAI.h</key>
<dict>
<key>hash2</key>
<data>
- IThULWmQt2RS9f8uhIVCj/9ZZKa5G20vUaJzCby0P9U=
+ hAXAZoFB6Ja0kc5Gm3Bo952k9fZUiSUPYM2f9gyTkQw=
</data>
</dict>
<key>Headers/JoyGemCallManager.h</key>
<dict>
<key>hash2</key>
<data>
- 4ZkuysTzaFha4/myXFF57XtlqM0e4bMJIZlamlMNqm8=
+ v9CC1YyWez/AeMXpqpyouz+LNIkBqq147kBPoPYEVK8=
</data>
</dict>
<key>Headers/JoyGemDeviceManager.h</key>
<dict>
<key>hash2</key>
<data>
- zMSjXsvAeHKCWlyAIRTc/D/BYBU8crV81VAMtiRCNZA=
+ b8SW0vyfvdZ5JjAexckdczSXWjl11+WIJDM6wuHhBEo=
</data>
</dict>
<key>Headers/JoyGemEnum.h</key>
<dict>
<key>hash2</key>
<data>
- ppJvM28BX4SQ+Bp40K+I9948VA34G8v2sowJEtO80vQ=
+ dSyxVyC1vMbliDqKuW0d31f2wCYxeWsx2/NHJQYPrRc=
</data>
</dict>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.abi.json</key>
<dict>
<key>hash2</key>
<data>
- c9qIPe1Wqd1NpKlpuawO+ORLNw5ws9/SFWK8GiWvotQ=
+ Xu9oOK+bUwZsz7YKaBS7sdDWZvQJwX6GCeM7UKDOIew=
</data>
</dict>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftdoc</key>
<dict>
<key>hash2</key>
<data>
- lFffbgJPWht+xRXKPA4Nv2rrNTUSt2wtt9PtaTTwK6w=
+ 4ZSTOVNx5VInV3CLCGXGsOKMICdleteG1O8aHABZCzw=
</data>
</dict>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftinterface</key>
<dict>
<key>hash2</key>
<data>
- c9qIPe1Wqd1NpKlpuawO+ORLNw5ws9/SFWK8GiWvotQ=
+ Xu9oOK+bUwZsz7YKaBS7sdDWZvQJwX6GCeM7UKDOIew=
</data>
</dict>
<key>Modules/JoyGemAI.swiftmodule/arm64-apple-ios.swiftmodule</key>
<dict>
<key>hash2</key>
<data>
- oIPD6jOI3lmqwRw8fQIjIdbh/igLDvY7QXuX2vHol4M=
+ nRKcutC82zySWegf6JkCelatcDI5wxHUuHo6O2D+Osc=
</data>
</dict>
<key>Modules/module.modulemap</key>